为了账号安全,请及时绑定邮箱和手机立即绑定

Windows中的Git符号链接

Windows中的Git符号链接

Git
潇湘沐 2019-07-05 10:14:17
Windows中的Git符号链接我们的开发人员混合使用Windows和基于Unix的操作系统,因此,在Unix机器上创建的符号链接成为Windows开发人员的一个问题。在windows(Msysgit)中,符号链接被转换为文本文件,其中包含指向的文件的路径。相反,我想将符号链接转换为实际的Windows符号链接。[医]更新)我必须解决的办法是:编写一个签出后脚本,递归地查找“symlink”文本文件。将它们替换为windows符号链接(使用mklink),其名称和扩展名与虚拟“符号链接”相同。通过在.git/info/EXECUTE中添加条目来忽略这些windows符号链接我没有落实这一点,但我认为这是解决这一问题的坚实办法。问题:如果有的话,你认为这种方法有什么坏处?这个结帐后脚本可以实现吗?也就是说,我能递归地找到虚拟的“符号链接”文件git创建的吗?有没有人写过这样的剧本?
查看完整描述

3 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

您可以通过查找具有120000,可能使用以下命令:

git ls-files -s | awk '/120000/{print $4}'

一旦您替换了链接,我建议将它们标记为git update-index --assume-unchanged,而不是将它们列在.git/info/exclude.


查看完整回答
反对 回复 2019-07-05
?
紫衣仙女

TA贡献1839条经验 获得超15个赞

我刚才问了一个完全相同的问题(一般不是在这里),最后提出了一个与OP的建议非常相似的解决方案。首先,我将直接回答问题1,2和3,然后我将张贴我最后使用的解决方案。

  1. 建议的解决方案确实有一些缺点,主要是因为存储库污染的可能性增加,或者在文件处于“Windows符号链接”状态时不小心添加重复文件。(下文“限制”一节将对此作更多介绍。)
  2. 是的,结帐后脚本是可实现的!也许不是作为一个字面上的帖子-

    git checkout

    步骤,但是下面的解决方案已经很好地满足了我的需求,所以不需要一个文字的签出脚本。
  3. 是!

解决办法:

我们的开发人员所处的情况与OP的大致相同:Windows和类Unix的主机、存储库和子模块混合在一起,有许多git符号链接,并且在MsysGit的发布版本中没有本地支持(尚未)来智能地在Windows主机上处理这些符号链接。

感谢josh lee指出git与特殊的filemode提交了符号链接。120000..有了这些信息,就可以添加一些git别名,允许在Windows主机上创建和操作git符号链接。

  1. 在Windows上创建Git符号链接

    git config --global alias.add-symlink '!'"$(cat <<'ETX'
    __git_add_symlink() {
      if [ $# -ne 2 ] || [ "$1" = "-h" ]; then
        printf '%b\n' \
            'usage: git add-symlink <source_file_or_dir> <target_symlink>\n' \
            'Create a symlink in a git repository on a Windows host.\n' \
            'Note: source MUST be a path relative to the location of target'
        [ "$1" = "-h" ] && return 0 || return 2
      fi
    
      source_file_or_dir=${1#./}
      source_file_or_dir=${source_file_or_dir%/}
    
      target_symlink=${2#./}
      target_symlink=${target_symlink%/}
      target_symlink="${GIT_PREFIX}${target_symlink}"
      target_symlink=${target_symlink%/.}
      : "${target_symlink:=.}"
    
      if [ -d "$target_symlink" ]; then
        target_symlink="${target_symlink%/}/${source_file_or_dir##*/}"
      fi
    
      case "$target_symlink" in
        (*/*) target_dir=${target_symlink%/*} ;;
        (*) target_dir=$GIT_PREFIX ;;
      esac
    
      target_dir=$(cd "$target_dir" && pwd)
    
      if [ ! -e "${target_dir}/${source_file_or_dir}" ]; then
        printf 'error: git-add-symlink: %s: No such file or directory\n' \
            "${target_dir}/${source_file_or_dir}" >&2
        printf '(Source MUST be a path relative to the location of target!)\n' >&2
        return 2
      fi
    
      git update-index --add --cacheinfo 120000 \
          "$(printf '%s' "$source_file_or_dir" | git hash-object -w --stdin)" \
          "${target_symlink}" \
        && git checkout -- "$target_symlink" \
        && printf '%s -> %s\n' "${target_symlink#$GIT_PREFIX}" "$source_file_or_dir" \
        || return $?
    }
    __git_add_symlink
    ETX
    )"

    用法:git add-symlink <source_file_or_dir> <target_symlink>,其中对应于源文件或目录的参数必须采用路径的形式。相对于目标符号链接。您可以按照通常使用的方式使用此别名。ln.

    例如,存储库树:

    dir/
    dir/foo/
    dir/foo/bar/
    dir/foo/bar/baz      (file containing "I am baz")
    dir/foo/bar/lnk_file (symlink to ../../../file)
    file                 (file containing "I am file")
    lnk_bar              (symlink to dir/foo/bar/)

    可以按以下方式在Windows上创建:

    git init
    mkdir -p dir/foo/bar/
    echo "I am baz" > dir/foo/bar/baz
    echo "I am file" > file
    git add -A
    git commit -m "Add files"
    git add-symlink ../../../file dir/foo/bar/lnk_file
    git add-symlink dir/foo/bar/ lnk_bar
    git commit -m "Add symlinks"
  2. 用NTFS硬链+结取代git符号

    git config --global alias.rm-symlinks '!'"$(cat <<'ETX'
    __git_rm_symlinks() {
      case "$1" in (-h)
        printf 'usage: git rm-symlinks [symlink] [symlink] [...]\n'
        return 0
      esac
      ppid=$$
      case $# in
        (0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
        (*) printf '%s\n' "$@" ;;
      esac | while IFS= read -r symlink; do
        case "$symlink" in
          (*/*) symdir=${symlink%/*} ;;
          (*) symdir=. ;;
        esac
    
        git checkout -- "$symlink"
        src="${symdir}/$(cat "$symlink")"
    
        posix_to_dos_sed='s_^/\([A-Za-z]\)_\1:_;s_/_\\\\_g'
        doslnk=$(printf '%s\n' "$symlink" | sed "$posix_to_dos_sed")
        dossrc=$(printf '%s\n' "$src" | sed "$posix_to_dos_sed")
    
        if [ -f "$src" ]; then
          rm -f "$symlink"
          cmd //C mklink //H "$doslnk" "$dossrc"
        elif [ -d "$src" ]; then
          rm -f "$symlink"
          cmd //C mklink //J "$doslnk" "$dossrc"
        else
          printf 'error: git-rm-symlink: Not a valid source\n' >&2
          printf '%s =/=> %s  (%s =/=> %s)...\n' \
              "$symlink" "$src" "$doslnk" "$dossrc" >&2
          false
        fi || printf 'ESC[%d]: %d\n' "$ppid" "$?"
    
        git update-index --assume-unchanged "$symlink"
      done | awk '
        BEGIN { status_code = 0 }
        /^ESC\['"$ppid"'\]: / { status_code = $2 ; next }
        { print }
        END { exit status_code }
      '
    }
    __git_rm_symlinks
    ETX
    )"
    
    git config --global alias.rm-symlink '!git rm-symlinks'  # for back-compat.

    用法:

    git rm-symlinks [symlink] [symlink] [...]

    这个别名可以一次地删除git符号链接。Symlink将替换为NTFS硬链接(在文件中)或NTFS连接(在目录中)。与“真”NTFS符号链接相比,使用硬链接+连接的好处是要创建UAC权限,不需要经过提升的UAC权限。

    要从子模块中删除符号链接,只需使用git内置的支持迭代它们:

    git submodule foreach --recursive git rm-symlinks

    但是,对于每一次如此激烈的行动,有一个逆转是很好的.

  3. 在Windows上恢复Git符号链接

    git config --global alias.checkout-symlinks '!'"$(cat <<'ETX'
    __git_checkout_symlinks() {
      case "$1" in (-h)
        printf 'usage: git checkout-symlinks [symlink] [symlink] [...]\n'
        return 0
      esac
      case $# in
        (0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
        (*) printf '%s\n' "$@" ;;
      esac | while IFS= read -r symlink; do
        git update-index --no-assume-unchanged "$symlink"
        rmdir "$symlink" >/dev/null 2>&1
        git checkout -- "$symlink"
        printf 'Restored git symlink: %s -> %s\n' "$symlink" "$(cat "$symlink")"
      done
    }
    __git_checkout_symlinks
    ETX
    )"
    
    git config --global alias.co-symlinks '!git checkout-symlinks'

    用法:git checkout-symlinks [symlink] [symlink] [...],这会使git rm-symlinks,有效地将存储库恢复到其自然状态(除了您的更改之外,保持原封不动)。

    对于子模块:

    git submodule foreach --recursive git checkout-symlinks
  4. 限制:

    • 路径中有空格的目录/文件/符号链接应该可以工作。但是标签还是新行?YMMV…(我的意思是:不要那样做,因为它不会工作)

    • 如果你或其他人忘了git checkout-symlinks在做一些有可能造成广泛后果的事情之前git add -A,本地存储库可能会以污染状态。

      使用我们以前的“示例回购”:

      echo "I am nuthafile" > dir/foo/bar/nuthafile
      echo "Updating file" >> file
      git add -A
      git status
      # On branch master
      # Changes to be committed:
      #   (use "git reset HEAD <file>..." to unstage)
      #
      #       new file:   dir/foo/bar/nuthafile
      #       modified:   file
      #       deleted:    lnk_bar           # POLLUTION
      #       new file:   lnk_bar/baz       # POLLUTION
      #       new file:   lnk_bar/lnk_file  # POLLUTION
      #       new file:   lnk_bar/nuthafile # POLLUTION
      #

      哇哦.。

      因此,在构建项目之前和之后,而不是在签出或推送之前,将这些别名作为Windows用户执行的步骤是很好的。但每一种情况都是不同的。这些别名对我来说已经足够有用了,所以不需要真正的结帐解决方案。

希望能帮上忙!

参考资料:

http:/git-scm.com/book/en/git-inals-Git-Objects

http:/Technnet.microsoft.com/en-us/Library/cc753194


  • POSIX的遵守情况(嗯,除了那些

    mklink

    当然)

    巴什主义!

  • 支持包含空格的目录和文件。
  • 零和非零退出状态代码(分别用于通信请求的命令的成功/失败)现在被正确保存/返回。
  • 这个

    add-symlink

    别名现在更像

    Ln(1)

    并且可以在存储库中的任何目录中使用,而不仅仅是存储库的根目录。
  • 这个

    rm-symlink

    别名(单数)已被

    rm-symlinks

    别名(复数),它现在接受多个参数(或者根本不接受参数,它像以前一样在存储库中查找所有的符号链接),用于选择性地将git符号链接转换为NTFS硬链接+连接。
  • 这个

    checkout-symlinks

    别名还被更新为接受多个参数(或根本不接受,=All),以选择性地逆转上述转换。

最后注:虽然我使用Bash3.2(甚至3.1)测试了加载和运行这些别名的方法,对于那些由于各种原因仍然停留在这些古老版本上的人来说,请注意,像这些版本一样古老的版本因其解析器错误而臭名昭著。如果您在尝试安装这些别名时遇到了问题,首先应该考虑的是升级shell(对于Bash,请使用CTRL+X、CTRL+V检查版本)。或者,如果您试图通过将它们粘贴到您的终端仿真器中来安装它们,您可能会更幸运地将它们粘贴到一个文件中并将其外包,例如

. ./git-win-symlinks.sh

祝好运!


查看完整回答
反对 回复 2019-07-05
  • 3 回答
  • 0 关注
  • 858 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信