Windows中的Git符号链接

我们的开发人员使用基于Windows和Unix的操作系统。 因此,在Unix机器上创建的符号链接成为Windows开发人员的一个问题。 在Windows(msysgit)中,符号链接被转换为文本文件,并带有它指向的文件的路径。 相反,我想将符号链接转换为实际的Windows符号链接。

我需要的( 更新的 )解决方案是:

  • 编写一个递归查找脚本,递归查找“符号链接”文本文件。
  • 将它们替换为具有相同名称和扩展名的windows符号链接(使用mklink)作为虚拟“符号链接”
  • 通过将条目添加到.git / info / exclude中,忽略这些窗口符号链接
  • 我没有实现这一点,但我相信这是解决这个问题的可靠方法。

    问题:

  • 你认为这种方法有什么缺点?
  • 这个后结帐脚本是否可以实现? 即我可以递归地找出假的“符号链接”文件git创建?
  • 有人有过这样的脚本吗?

  • 您可以通过查找具有120000模式的文件来找到符号链接,可能使用以下命令:

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

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


    我一直在问这个完全相同的问题(不是在这里,一般情况下),并最终提出了一个与OP的主张非常类似的解决方案。 首先我会直接回答问题1 2和3,然后我会发布我最终使用的解决方案。

  • 提出的解决方案确实存在一些缺点,主要是因为存储库污染的可能性增加,或者在它们处于“Windows符号链接”状态时意外添加重复文件。 (更多信息请参见下面的“限制”。)
  • 是的,结账后脚本是可以实施的! 也许不是一个字面上的后git checkout步骤,但下面的解决方案已经很好地满足了我的需求,以至于不需要字面的结账后脚本。
  • 是!
  • 解决方案:

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

    感谢Josh Lee指出git使用特殊文件模式120000提交符号链接的事实。 有了这些信息,可以添加一些git别名,以便在Windows主机上创建和操作git符号链接。

  • 在Windows上创建git符号链接

    2014-11-12更新 (见下文)

    git config --global alias.add-symlink '!__git_add_symlink(){
        argv=($@)
        argc=${#argv[@]}
    
        # Look for options
        options=(" -h")
        o_help="false"
        case "${argv[@]}" in *" -h"*) o_help="true" ;; esac
        if [ "$o_help" == "true" -o "$argc" -lt "2" ]; then
            echo "
    Usage: git add-symlink <target> <link>
    
    * <target> is a RELATIVE PATH, respective to <link>.
    * <link> is a RELATIVE PATH, respective to the repository'''s root dir.
    * Command must be run from the repository'''s root dir."
            return 0
        fi
    
        target_arg=${argv[0]}
        link_arg=${argv[1]}
    
        if [ ! -e "$target_arg" ]; then
            echo "ERROR: Target $target_arg does not exist; not creating invalid symlink."
            return 1
        fi
    
        hash=$(echo -n "$target_arg" | git hash-object -w --stdin)
        git update-index --add --cacheinfo 120000 "$hash" "$link_arg"
        git checkout -- "$link_arg"
    
    }; __git_add_symlink "$@"'
    

    用法: git add-symlink <src> <dst> ,其中<src>是要链接到的文件或目录的当前位置的相对引用 (相对于<dst> ), <dst>相对引用 (相对于存储库的根)到链接所需的目的地。

    例如,存储库树:

    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"
    
  • 用NTFS硬链接+连接替换git符号链接

    git config --global alias.rm-symlink '!__git_rm_symlink(){
        git checkout -- "$1"
        link=$(echo "$1")
        POS=$'''/'''
        DOS=$'''\'''
        doslink=${link//$POS/$DOS}
        dest=$(dirname "$link")/$(cat "$link")
        dosdest=${dest//$POS/$DOS}
        if [ -f "$dest" ]; then
            rm -f "$link"
            cmd //C mklink //H "$doslink" "$dosdest"
        elif [ -d "$dest" ]; then
            rm -f "$link"
            cmd //C mklink //J "$doslink" "$dosdest"
        else
            echo "ERROR: Something went wrong when processing $1 . . ."
            echo "       $dest may not actually exist as a valid target."
        fi
    }; __git_rm_symlink "$1"'
    
    git config --global alias.rm-symlinks '!__git_rm_symlinks(){
        for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do
            git rm-symlink "$symlink"
            git update-index --assume-unchanged "$symlink"
        done
    }; __git_rm_symlinks'
    

    用法:

    git rm-symlink dir/foo/bar/lnk_file
    git rm-symlink lnk_bar
    git update-index --assume-unchanged dir/foo/bar/lnk_file
    git update-index --assume-unchanged lnk_bar
    

    这将逐个删除git符号链接,将其替换为NTFS硬链接(在文件的情况下)或NTFS连接点(在目录的情况下)。 使用硬连接+连接而不是“真正的”NTFS符号连接的好处是不需要提升UAC权限以便创建它们。 最后,在您自己的闲暇时间,您可以选择使用git update-index取消修改(或不修改)符号链接。

    为了方便起见,你也可以运行:

    git rm-symlinks
    

    这将删除当前存储库中的所有git符号链接,并根据需要将其替换为硬链接+连接,并自动标记git status将忽略的更改。

    要从子模块中删除符号链接,只需使用git的内置支持来遍历它们即可:

    git submodule foreach --recursive git rm-symlinks
    

    但是,对于这样的每一个激烈的行动,逆转是很好的... ...

  • 在Windows上恢复git符号链接

    git config --global alias.checkout-symlinks '!__git_checkout_symlinks(){
        POS=$'''/'''
        DOS=$'''\'''
        for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do
            git update-index --no-assume-unchanged "$symlink"
            dossymlink=${symlink//$POS/$DOS}
            cmd //C rmdir //Q "$dossymlink" 2>/dev/null
            git  checkout -- "$symlink"
            echo "Restored git symlink $symlink <<===>> $(cat $symlink)"
        done
    }; __git_checkout_symlinks'
    

    用法: git checkout-symlinks ,它撤销git rm-symlinks ,有效地将存储库恢复到它的自然状态(除了你的更改,它应该保持不变)。

    对于子模块:

    git submodule foreach --recursive git checkout-symlinks
    
  • 限制:

  • 只能从repo的根目录运行,否则,会发生奇怪的事情...
  • 输入其中一个别名时,基于标签的自动完成功能会中断
  • 如果人们在做一些像git add -A类的工作之前忘记了git checkout-symlinks ,他们可能会污染回购!

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

    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-Internals-Git-Objects

    http://technet.microsoft.com/en-us/library/cc753194

    UPDATE 2014-11-12:因为我个人只是大量使用上面的rm-symlinkscheckout-symlinks别名,所以我设法忽略了add-symlink别名中相当讨厌的错误。 之前, -n没有被传递给echo语句,该语句负责创建git symlink文件,该文件稍后将作为add-symlink操作的一部分添加到暂存区域中。 这意味着一个尾随的换行符(Windows主机上的0x0D 0x0A )被添加到使用add-symlink创建的所有git符号add-symlink 。 虽然这些git符号链接仍然可以在Windows主机上使用rm-symlinks “可移动”,但如果它们曾经被提交到公共仓库并且后来在基于posix的真正系统上克隆,那么这些链接总是会在另一个系统上出现侧。 此问题已得到解决,并且add-symlink现在应按预期工作。


    最新版本的git scm(testet 2.11.1)允许启用符号链接。 但是您必须再次使用符号链接克隆存储库git clone -c core.symlinks=true <URL> 。 您需要使用管理员权限运行此命令。 使用mklink也可以在Windows上创建符号链接。 看看wiki。

    在这里输入图像描述

    链接地址: http://www.djcxy.com/p/78103.html

    上一篇: Git Symlinks in Windows

    下一篇: How to check if a symlink exists