【问题标题】:Git symbolic links in WindowsWindows 中的 Git 符号链接
【发布时间】:2011-08-20 12:12:58
【问题描述】:

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

我必须的(更新)解决方案是:

  • 编写一个以递归方式查找“符号链接”文本文件的结帐后脚本。
  • 将它们替换为与虚拟“符号链接”具有相同名称和扩展名的 Windows 符号链接(使用 mklink)
  • 通过在 .git/info/exclude 中添加条目来忽略这些 windows 符号链接

我还没有实现这个,但我相信这是解决这个问题的可靠方法。

问题:

  1. 您认为这种方法有哪些缺点(如果有的话)?
  2. 这个结帐后脚本甚至可以实现吗?即我可以递归找出 git 创建的虚拟“符号链接”文件吗?
  3. 有人已经编写过这样的脚本了吗?

【问题讨论】:

  • 虽然 Git 支持符号链接,但我强烈建议不要将它们作为链接存储在您的存储库中,尤其是如果您也在 Windows 上使用该代码。
  • @Greg Hewgill - 我完全同意你的看法。不幸的是,我们代码库的性质需要符号链接......所以删除它们不是我们的选择。
  • 你也可以在 msysgit 邮件列表上问他们为什么一开始没有那样实现它。
  • @GregHewgill 为什么不呢? Windows 支持符号链接和联结——在我看来,这确实是 Windows 版本的 Git 中缺少的功能......
  • With "Developer Mode" enabled in Windows 10, creating symlinks doesn't require Administrator rights!(其他人对投票较少的答案发表了同样多的评论,但我没有看到他们。希望这个评论对未来的读者更加可见。)

标签: windows git symlink


【解决方案1】:

不久前我问过这个完全相同的问题(不是在这里,只是一般情况下),并最终提出了与 OP 的提议非常相似的解决方案。 我将发布我最终使用的解决方案。

但首先我将直接回答 OP 的 3 个问题:

问:“您认为这种方法有什么缺点(如果有的话)?”

答:建议的解决方案确实有一些缺点,主要是关于存储库污染的可能性增加,或者在它们处于“Windows 符号链接”状态时意外添加了重复文件。 (在下面的“限制”下对此进行了详细介绍。)

问:“这个结帐后脚本甚至可以实现吗?即我可以递归地找出 git 创建的虚拟“符号链接”文件吗?”

答:是的,可以执行结帐后脚本!也许不是文字后git checkout 步骤,但下面的解决方案已经很好地满足了我的需求,因此不需要文字后结帐脚本。

问:“有人已经写过这样的剧本了吗?”

答:是的!

解决方案:

我们的开发人员与 OP 的情况大致相同:混合了 Windows 和类 Unix 主机、存储库和具有许多 git 符号链接的子模块,并且在 MsysGit 的发布版本中还没有原生支持以智能处理这些符号链接在 Windows 主机上。

感谢 Josh Lee 指出 git 使用特殊文件模式 120000 提交符号链接这一事实。有了这些信息,就可以添加一些允许在 Windows 主机上创建和操作 git 符号链接的 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 &lt;source_file_or_dir&gt; &lt;target_symlink&gt;,其中与源文件或目录对应的参数必须采用路径的形式相对于目标符号链接。您可以像平常一样使用此别名使用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 符号链接一个接一个或一次全部删除。符号链接将替换为 NTFS 硬链接(在文件的情况下)或 NTFS 连接(在目录的情况下)。使用硬链接+连接而不是“真正的”NTFS 符号链接的好处是,创建它们时不需要提升的 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 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

最后更新:2019-03-13

  • POSIX 合规性(当然,除了那些 mklink 调用)- 不再有 Bashisms!
  • 支持包含空格的目录和文件。
  • 现在可以正确保留/返回零和非零退出状态代码(分别用于传达请求命令的成功/失败)。
  • add-symlink 别名现在更像ln(1),可以从存储库中的任何目录使用,而不仅仅是存储库的根目录。
  • rm-symlink 别名(单数)已被 rm-symlinks 别名(复数)取代,它现在接受多个参数(或根本没有参数,它可以像以前一样在整个存储库中找到所有符号链接)选择性地将 git 符号链接转换为 NTFS 硬链接+连接。
  • checkout-symlinks 别名也已更新为接受多个参数(或根本不接受,== 全部),以选择性地反转上述转换。

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

. ./git-win-symlinks.sh

祝你好运!

【讨论】:

  • 你能在这里看看吗? stackoverflow.com/questions/21403772/…
  • 这是一个非常棒的脚本,但是有什么理由让我在使用 git add-symlink 创建的一些文件的末尾随机添加“git”这个词?跨度>
  • 另外,如果你的文件名包含“-h”,你就会得到用法。还是很有用的脚本!
  • 您的git add-symlink 食谱对我来说非常有价值。非常感谢。
  • 有没有办法使用钩子自动执行这些脚本?
【解决方案2】:

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

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

替换链接后,我建议将它们标记为 git update-index --assume-unchanged 未更改,而不是在 .git/info/exclude 中列出它们。

【讨论】:

  • 我不得不用 gawk 替换 msysgit 的 awk,但除此之外它工作得很好。谢谢!
  • 赫洛肯。您是否介意共享您的脚本来检查符号链接文本文件并使用 mklink 在 Windows 上用符号链接替换它们。虽然这实际上对我们有用,但 --assume-unchanged 部分却没有。切换到另一个分支 git 表示符号链接文件已更改,需要先提交,而 git status 表示没有更改..有什么想法吗?
  • 这是一个我刚刚放在一起的 PowerShell - gist.github.com/ferventcoder/7995025
  • @flungo 打印第四列的方式比使用 GNU awk 更便携。例如:git ls-files -s | grep '^12' | cut -f2(第二个制表符分隔的列;其他列以空格分隔)
  • 一个用于 Cygwin/bash 标记所有符号链接不变的衬垫:for f in `git ls-files -s | awk '/120000/{print $4}'`; do git update-index --assume-unchanged $f; done
【解决方案3】:

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

【讨论】:

  • 这对我不起作用。我为 Windows 重新安装了 git,记得选中符号链接复选框并再次克隆我的项目。我的tslint.json 文件引用父目录中的文件仍然包含../tslint.json。可惜,因为这看起来确实是其中提出的所有解决方案中最简单的。
  • @JanAagaard 你必须像这样克隆它:git clone -c core.symlinks=true &lt;URL&gt; 在 Windows 上你必须以管理员权限运行它。
  • @ARF "启动 gpedit.msc(即组策略编辑器)并将帐户添加到计算机配置\Windows 设置\安全设置\本地策略\用户权限分配\创建符号链接。 "
  • @sirlunchalot 感谢您的帮助。从那以后,我意识到我的问题是我的用户是管理员组的一部分,并且此属性对这些用户没有影响。它们需要 git 不做的 UAC 提升。
  • Admin rights are not necessary 在 Windows 10 创意者更新的“开发者模式”中。感谢@dennis his comment。
【解决方案4】:

2020/2021 TL;DR 答案

  1. 在 Windows 10/11 中启用“开发者模式”——授予 mklink 权限
  2. 确保在 git 中启用符号链接
    • git config --global core.symlinks true
    • 或
    • 安装 msysgit 时勾选复选框

切换分支将强制重新创建丢失的符号链接。

小心,在 Windows 上对 git 中的符号链接的支持是相对新的。 有一些 bug 仍然会影响一些 git 客户端。 值得注意的是,由于(fixed)regression in libgit2,在某些程序中具有相对 (..) 路径的符号链接会被破坏。 例如,GitKraken 受此影响,因为它们正在等待 nodegit 将 libgit2 从 v0.x(回归)更新为 v1.x(固定)。

【讨论】:

  • 我所有的本地存储库都有 core.symlinks=false 这将覆盖您的解决方案。知道是什么自动生成了这个本地配置吗?可能在不选中复选框的情况下安装适用于 Windows 的 Git?
  • @gravidThoughts 您安装了哪些 git 客户端?也许一些工具正在这样做?在新克隆上是这样吗?
  • 另外,您必须重新克隆存储库以使符号链接与它一起使用
【解决方案5】:

由于 GIT 的情况发生了变化,因为这里发布了很多这些答案,所以正确的说明是让符号链接在 Windows 中正常工作

2018 年 8 月


1.确保安装 git 并支持符号链接

2。告诉 Bash 创建硬链接而不是符号链接

编辑 -- (git 文件夹)/etc/bash.bashrc

添加到底部 - MSYS=winsymlinks:nativestrict

3。设置 git config 以使用符号链接

git config core.symlinks true

或

git clone -c core.symlinks=true <URL>

注意:我已尝试将其添加到全局 git 配置中,但目前它对我不起作用,因此我建议将其添加到每个 repo...

4.拉回购

注意:除非您在最新版本的 Windows 10 中启用了开发者模式,否则您需要以管理员身份运行 bash 来创建符号链接

5.重置所有符号链接(可选) 如果您有现有的存储库,或者正在使用子模块,您可能会发现未正确创建符号链接,因此要刷新存储库中的所有符号链接,您可以运行这些命令。

find -type l -delete
git reset --hard

注意:这将重置自上次提交以来的所有更改,因此请确保您已先提交

【讨论】:

    【解决方案6】:

    应该在msysgit中实现,但是有两个缺点:

    • 符号链接仅在 Windows Vista 及更高版本中可用(在 2011 年应该不是问题,但它是...),因为旧版本仅支持目录连接。
    • (大问题)Microsoft 认为符号链接存在安全风险,因此默认情况下只有管理员可以创建它们。您需要提升 git 进程的权限或使用 fstool 在您工作的每台机器上更改此行为。

    我进行了快速搜索,目前正在积极开展相关工作,请参阅问题 224。

    【讨论】:

    • 更新:由于上述原因,该问题已作为 wontfix 关闭。讨论表明,可以通过对补丁进行更多工作来接受修复(例如,仅在有效的情况下使用符号链接)。
    • A.) 目前 msysgit 根本不支持符号链接——所以为什么不让它检测“哦,你在使用 NTFS 的 vista 让我使用符号链接”或“哦,你在一个支持与 NTFS 连接的操作系统,让我使用这些”,或者“哦,你在 Windows 98/fat32 上,让我回退到没有这个功能,而是给你一个警告!”然后 B.) 几乎所有微软的开发人员。如果您不以管理员身份运行工具,这些工具将无法正常工作(至少不适用于它们的所有功能)——IT 中的每个人都知道开发人员需要在自己的机器上成为管理员。
    • 虽然我确实在 Admin 帐户中运行某些机器,但我并没有在我的开发机器上遵循这种理念。我总是以启用 UAC 的普通用户身份运行。我为需要提升权限的操作打开了一个单独的控制台。至于实现这个,它归结为某人(比如你)自愿实现它。 msysgit 开发人员不以慈善着称...
    • @djs 用户必须使用“以管理员身份运行”打开命令提示符。它几乎完全以管理员用户身份运行,这完全改变了环境。无法以同样属于 Admin 组的用户身份运行“mklink /d”。它不会 UAC 提示。它会失败,永远。它只有两种工作方式:字面上作为管理员用户(RunAs Verb),或具有组策略更改的非管理员用户。连接点应该是默认设置,并且应该被所有工具识别。 “安全风险”是 Windows 上的符号链接可以“重定向”SMB 共享。这是一种痛苦和残酷。
    • 2016 年 12 月宣布,Windows 10 中的符号链接不再是管理员操作。 blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/…
    【解决方案7】:

    简短回答:如果您可以启用开发者模式,它们现在得到很好的支持。

    来自https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/

    现在在 Windows 10 Creators Update 中,用户(具有管理员权限)可以 先开启开发者模式,然后机器上的任何用户都可以运行 无需提升命令行控制台的 mklink 命令。

    是什么推动了这种变化?符号链接的可用性和使用是一个很大的问题 与现代开发者打交道:

    许多流行的开发工具,如 git 和包管理器,如 npm 在创建存储库或包时识别并保留符号链接, 分别。当这些存储库或包被恢复时 在其他地方,符号链接也被恢复,确保磁盘空间(和 用户的时间)没有被浪费。

    “创作者更新”的所有其他公告很容易被忽略,但如果您启用开发者模式,您可以在没有提升权限的情况下创建符号链接。您可能需要重新安装 git 并确保启用了符号链接支持,因为默认情况下它不是。

    【讨论】:

    • gpedit.msc -> Local Computer Policy -> Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment 一直是分配用户权限的规范方式喜欢SeCreateSymbolicLink 和多年的朋友。除了来自 Resource Kit 或 PowerShell 的 ntrights.exe ...
    【解决方案8】:

    我建议您不要在 repo 中使用符号链接。将实际内容存储在 repo' 中,然后将符号链接放在指向内容的 repo' 之外。

    假设您正在使用 repo 来比较在 *nix 上托管您的网站与在 win 上托管。将内容存储在您的存储库中',比如说/httpRepoContent 和c:\httpRepoContent,这是通过 GIT、SVN 等同步的文件夹。

    然后,将您的 Web 服务器的内容文件夹(/var/www 和 c:\program files\web server\www {名称并不重要,如果必须编辑})替换为指向您的存储库中内容的符号链接。 Web 服务器会在“正确”的位置看到内容,但您可以使用源代码控制。

    但是,如果您需要在 repo' 中使用符号链接,您将需要研究类似某种前/后提交脚本之类的东西。我知道您可以使用它们来做一些事情,例如通过格式化程序解析代码文件,因此应该可以在平台之间转换符号链接。

    如果有人知道如何为通用源代码控制 SVN GIT MG 编写这些脚本的好地方,请添加评论。

    【讨论】:

    • 最后,我选择了这种方法来创建一个符号链接输出文件夹,并创建指向原始文件所在位置的符号链接。即使在我更改了 .git/config 设置 core.symlinks = true 后,另一种方法也不起作用。只有符号链接文件被保存到 repo 而不是数据。符号链接上的文件夹时间戳也有问题,因此 git bash 永远不会看到文件夹中的文件发生更改。
    • @Eggs 你可能已经看到了,我猜,链接在 repo 中,所以 git 保存了它,简单。但问题是目标在 repo 之外,并且 git 不遵循指向目标数据的链接。在 linux 上,你有一种可以解决这个问题的链接,它基本上让你有两条路径指向存储在磁盘上的相同数据;我感觉新的 Windows 现在可以做到这一点。不管怎样,我仍然认为它不会像人们想要的那样。
    • @thecoshman 这不是解决方案,而是解决方法。但是,有时这不是一种选择。我有一个带有 git-annex 的存储库,由于符号链接,它的所有架构都可以工作。
    【解决方案9】:

    对于在 Vista、Win7 或更高版本上使用 CygWin 的用户,本机 git 命令可以创建 Windows 应用程序(例如 Android Studio)识别的“正确”符号链接。您只需将CYGWIN 环境变量设置为包含winsymlinks:native 或winsymlinks:nativestrict 即可:

    export CYGWIN="$CYGWIN winsymlinks:native"
    

    这样做的缺点(也是一个重要的缺点)是 CygWin shell 必须“以管理员身份运行”才能获得创建此类符号链接所需的操作系统权限。但是,一旦创建它们,使用它们不需要特殊权限。只要它们没有被其他开发人员在存储库中更改,git 之后就可以正常使用普通用户权限。

    就我个人而言,仅用于由 Windows 应用(即非 CygWin)导航的符号链接,因为这增加了难度。

    有关此选项的更多信息,请参阅此 SO 问题:How to make symbolic link with cygwin in Windows 7

    【讨论】:

    • Cygwin 官方文档不鼓励使用winsymlinks:native。使用“开发者模式”,您似乎不再需要在 Windows 10 中以提升的权限运行。
    • 这对我没有帮助,但 export MSYS=winsymlinks:nativestrict 有帮助
    【解决方案10】:

    我刚刚尝试使用 Git 2.30.0(2020-12-28 发布)。

    这不是一个完整的答案,但仍然是一些有用的花絮。 (随意蚕食你自己的答案。)

    Git 维基条目

    安装 Git for Windows 时有一个文档链接

    此链接会将您带到此处:https://github.com/git-for-windows/git/wiki/Symbolic-Links -- 这是一个相当长的讨论。

    仅供参考:至少有三种“链接类型”

    只是为了强调这个 wiki 条目的一个重要方面:我不知道这一点,但有几种方式,所有这些方式表面上都是“某种”符号链接,但在技术层面上是非常不同的:

    • git bash 的“ln -s”
      这只是复制东西。好家伙。这出乎我的意料。
      (仅供参考:Plain Cygwin 不会这样做。Mobaxterm 不会这样做。相反,它们都创建了它们的 stat 命令实际上识别为“符号链接”的东西。)
    • cmd.exe 的内置“mklink”命令带有“/D”参数
      这会创建一个目录符号链接。 (见MS Docs)
    • cmd.exe 的内置“mklink”命令带有“/J”参数
      它创建了一个目录连接 AKA 软链接 AKA 重解析点。 (见MS Docs)

    发行说明条目

    符号链接也在the release notes 中不断弹出。从 2.30.0 开始,这里仍然被列为“已知问题”:

    在 1703 之前的 Windows 10 上,或关闭开发人员模式时,克隆带有符号链接的存储库时需要特殊权限,因此默认情况下禁用对符号链接的支持。使用git clone -c core.symlinks=true &lt;URL&gt;开启,详情见here。

    【讨论】:

      【解决方案11】:

      这是一个批处理脚本,用于转换存储库中的符号链接,仅适用于文件,基于 Josh Lee 的回答。带有一些额外检查管理员权限的脚本位于https://gist.github.com/Quazistax/8daf09080bf54b4c7641。

      @echo off
      pushd "%~dp0"
      setlocal EnableDelayedExpansion
      
      for /f "tokens=3,*" %%e in ('git ls-files -s ^| findstr /R /C:"^120000"') do (
           call :processFirstLine %%f
      )
      REM pause
      goto :eof
      
      :processFirstLine
      @echo.
      @echo FILE:    %1
      
      dir "%~f1" | find "<SYMLINK>" >NUL && (
        @echo FILE already is a symlink
        goto :eof
      )
      
      for /f "usebackq tokens=*" %%l in ("%~f1") do (
        @echo LINK TO: %%l
      
        del "%~f1"
        if not !ERRORLEVEL! == 0 (
          @echo FAILED: del
          goto :eof
        )
      
        setlocal
        call :expandRelative linkto "%1" "%%l"
        mklink "%~f1" "!linkto!"
        endlocal
        if not !ERRORLEVEL! == 0 (
          @echo FAILED: mklink
          @echo reverting deletion...
          git checkout -- "%~f1"
          goto :eof
        )
      
        git update-index --assume-unchanged "%1"
        if not !ERRORLEVEL! == 0 (
          @echo FAILED: git update-index --assume-unchanged
          goto :eof
        )
        @echo SUCCESS
        goto :eof
      )
      goto :eof
      
      :: param1 = result variable
      :: param2 = reference path from which relative will be resolved
      :: param3 = relative path
      :expandRelative
        pushd .
        cd "%~dp2"
        set %1=%~f3
        popd
      goto :eof
      

      【讨论】:

      • 当已经存在如此冗长和冗长的答案时,一个无证的答案真的没有多大用处。
      【解决方案12】:

      我一直在我的文档根目录和 git repo 目录之间使用符号链接。我喜欢把它们分开。在 Windows 上,我使用 mklink /j 选项。结似乎让 git 表现正常:

      &gt;mklink /j &lt;location(path) of link&gt; &lt;source of link&gt;

      例如:

      &gt;mklink /j c:\gitRepos\Posts C:\Bitnami\wamp\apache2\htdocs\Posts

      【讨论】:

      • 小心使用 Windows 资源管理器和连接;它不会区分连接点和基本位置,删除将递归到目标并删除它的内容,而删除符号链接只会删除符号链接。只是粗心的陷阱。
      • 实际上,刚刚在最新的 Windows7 上测试过,现在已经不行了,所以在过去几年的某个时候,连接点的处理得到了改进。
      【解决方案13】:

      我一直在寻找一种简单的解决方案来处理 Windows 上的 unix 符号链接。非常感谢您提供上述 Git 别名。 可以对 rm-symlinks 进行一点优化,这样它就不会删除目标文件夹中的文件,以防别名再次意外运行。请观察循环中的新 if 条件,以确保在运行逻辑之前文件还不是目录的链接。

      git config --global alias.rm-symlinks '!__git_rm_symlinks(){
      for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do
          *if [ -d "$symlink" ]; then
            continue
          fi*
          git rm-symlink "$symlink"
          git update-index --assume-unchanged "$symlink"
      done
      }; __git_rm_symlinksenter 
      

      【讨论】:

        【解决方案14】:

        我们使用的一个简单技巧是连续两次调用git add --all。

        例如,我们的 Windows 7 提交脚本调用:

        $ git add --all
        $ git add --all
        

        第一次添加将链接视为文本并添加要删除的文件夹。

        第二个添加正确地遍历链接并通过恢复文件撤消删除。

        它不如其他一些提议的解决方案优雅,但它是对我们添加了符号链接的一些遗留环境的简单修复。

        【讨论】:

          【解决方案15】:

          这是一个用 windows 替换 unix 符号链接的 powershell 脚本

          # This fixes Permission denied errors you might get when
          #  there are git symlinks being used on repositories that
          #  you share in both POSIX (usually the host) and Windows (VM).
          #
          # This is not an issue if you are checking out the same
          #  repository separately in each platform. This is only an issue
          #  when it's the same working set (aka make a change w/out
          #  committing on OSX, go to Windows VM and git status would show
          #  you that change).
          #
          # Based on this answer on stack overflow: http://stackoverflow.com/a/5930443/18475
          #
          # No warranties, good luck
          #
          # MUST BE RUN IN ELEVATED POWER SHELL
          
          $ROOT = $PWD
          
          $symlinks = &git ls-files -s | gawk '/120000/{print $4}'
          foreach ($symlink in $symlinks) {
            $content = &Get-Content $symlink
            $content = $content.Replace("/", "\")
            $filename = $symlink.Split("/")[-1]
            cd (dirname $symlink)
            rm $filename
            echo Linking $content -> $filename
            New-Item -ItemType SymbolicLink -Path $filename -Target $content
            &git update-index --assume-unchanged $symlink
            cd $ROOT
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-03
            • 2020-04-25
            • 1970-01-01
            • 2010-11-29
            • 2014-11-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多