Windows中的Git符号链接

350

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

我对此的解决方案(已更新)如下:

  • 编写一个post-checkout脚本,递归查找“symbolic link”文本文件。
  • 用与虚拟的“symbolic link”名称和扩展名相同的Windows符号链接(使用mklink)替换它们。
  • 通过向文件.git/info/exclude添加一个条目来忽略这些Windows符号链接。

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

  1. 您认为这种方法有哪些缺点(如果有的话)?
  2. 这个post-checkout脚本是否可行?也就是说,我能递归查找Git创建的虚拟“symlink”文件吗?

7
尽管 Git 支持符号链接,但我强烈建议不要将它们作为链接存储在代码库中,尤其是如果您还在 Windows 上使用该代码。 - Greg Hewgill
5
我完全同意你的观点。不幸的是,我们代码库的性质要求使用符号链接... 因此,对我们来说删除它们并不是一个选项。 - Ken Hirakawa
14
您也可以在msysgit邮件列表上询问他们为什么一开始没有这样实现。 - drizzd
14
为什么不呢?Windows 支持符号链接和联接点,所以对我来说,在 Windows 版本的 Git 中,这似乎是一个缺失的功能... - BrainSlugs83
19
在Windows 10中启用"开发者模式"后,创建符号链接不需要管理员权限!(其他人已在得票较少的答案上评论,但我没有看到。希望这个评论对未来的读者更加可见。) - Dave Pascua
显示剩余4条评论
18个回答

222

更新说明

对于大多数在Windows上遇到符号链接和 git 以及与 *nix 系统共享仓库的问题的开发人员来说,这个主题是一个已解决的问题 - 只要你稍微更新一下对 mklink 的理解并打开开发者模式。

在深入讨论以下 git 技巧之前,请参阅此 更现代的答案

早期系统:

有一段时间我也在问同样的问题(不是在这里,只是普遍地),最终得出了与 OP 提出的建议非常相似的解决方案。我会发布我最终使用的解决方案。

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

Q: “您认为此方法有哪些缺点?”

A: 对于所提出的解决方案确实存在一些缺点,主要涉及增加仓库污染的潜力或在它们处于“Windows 符号链接”状态时意外添加重复文件。(详见下文的“限制”部分。)

Q: “这个提交后脚本是否可行?即我是否可以递归地找到git创建的虚拟“符号链接”文件?”

A: 是的,提交后脚本是可行的!也许不会像字面意义上的post-git checkout步骤那样,但下面的解决方案已经足够满足我的需求了,因此不需要字面意义上的提交后脚本。

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

A: 是的!

解决方案:

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

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

  1. Creating git symlinks on Windows

     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
     )"
    

    Usage: git add-symlink <source_file_or_dir> <target_symlink>, where the argument corresponding to the source file or directory must take the form of a path relative to the target symlink. You can use this alias the same way you would normally use ln.

    E.g., the repository tree:

     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/)
    

    Can be created on Windows as follows:

     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. Replacing git symlinks with NTFS hardlinks+junctions

     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.
    

    Usage:

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

    This alias can remove git symlinks one-by-one or all-at-once in one fell swoop. Symlinks will be replaced with NTFS hardlinks (in the case of files) or NTFS junctions (in the case of directories). The benefit of using hardlinks+junctions over "true" NTFS symlinks is that elevated UAC permissions are not required in order for them to be created.

    To remove symlinks from submodules, just use git's built-in support for iterating over them:

     git submodule foreach --recursive git rm-symlinks
    

    But, for every drastic action like this, a reversal is nice to have...

  3. Restoring git symlinks on Windows

     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'
    

    Usage: git checkout-symlinks [symlink] [symlink] [...], which undoes git rm-symlinks, effectively restoring the repository to its natural state (except for your changes, which should stay intact).

    And for submodules:

     git submodule foreach --recursive git checkout-symlinks
    
  4. Limitations:

    • Directories/files/symlinks with spaces in their paths should work. But tabs or newlines? YMMV… (By this I mean: don’t do that, because it will not work.)

    • If yourself or others forget to git checkout-symlinks before doing something with potentially wide-sweeping consequences like git add -A, the local repository could end up in a polluted state.

      Using our "example repo" from before:

      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
      #
      

      Whoops...

      For this reason, it's nice to include these aliases as steps to perform for Windows users before-and-after building a project, rather than after checkout or before pushing. But each situation is different. These aliases have been useful enough for me that a true post-checkout solution hasn't been necessary.

参考文献:

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

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

最后更新时间:2019年3月13日

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

最后说明:虽然我已经测试了使用Bash 3.2(甚至是3.1)加载和运行这些别名,为那些因各种原因仍然停留在古老版本上的人提供了帮助,但请注意,像这样旧的版本因其解析器错误而臭名昭著。如果您在尝试安装这些别名时遇到问题,您应该首先考虑升级您的Shell(对于Bash,请使用CTRL + X,CTRL + V检查版本)。或者,如果您正在尝试通过将它们粘贴到终端仿真器中来安装它们,您可以将它们粘贴到文件中并进行源化,例如

. ./git-win-symlinks.sh

这是一个非常棒和精彩的脚本,但是我使用 git add-symlink 创建一些文件时,它是否有任何理由在某些文件末尾随机添加单词“git”? - Peter Turner
此外,如果您的文件名包含“-h”,您将获得用法说明。仍然是非常有用的脚本! - Peter Turner
你的 git add-symlink 配方对我来说非常有价值。非常感谢。 - Dan Lenski
谢谢分享,我受到启发写了一个脚本,可以使用相对路径到 pwd 来创建符号链接,而不是仓库根目录。https://coderwall.com/p/z86txw/make-symlink-on-windows-in-a-git-repo - mrkschan
2
有没有办法通过钩子自动执行这些脚本? - ARF
显示剩余7条评论

150

2020+ TL;DR 答案

  1. 在 Windows 10/11 中启用“开发者模式”——赋予 mklink 权限
  2. 确保在 git 中启用符号链接,可以通过以下方式之一实现:
    • 系统设置:在安装 msysgit 时勾选复选框
    • 全局设置git config --global core.symlinks true
    • 本地设置git config core.symlinks true

小心,在Windows上使用git的符号链接支持是相对较新的。 仍然有一些bug会影响一些git客户端。 特别是,由于libgit2中的一个修复, 一些程序在检出时会破坏带有“父级”(..)路径的符号链接。 例如,GitKraken受到此影响,因为他们正在等待nodegit更新libgit2v0.x(回归)到v1.x(修复)。


重新创建丢失/损坏的符号链接

有多个git客户端报告了不同程度的成功,其中一个选项是(越来越强制和“危险”)

  • 检出: git checkout -- path/to/symlink
  • 恢复(自git v2.23.0起): git restore -- path/to/symlink
  • 切换分支(切出再切回来)
  • 硬重置: git reset --hard
  • 删除本地仓库并重新克隆

故障排除

git config --show-scope --show-origin core.symlinks 将显示设置的级别(也称为“范围”),持久化该设置的配置文件(也称为“来源”)以及设置的当前值。很可能是“本地”配置覆盖了“全局”或“系统”设置。 git config --unset core.symlinks 将清除“本地”设置,从而使更高级别的设置生效。


@gravidThoughts 你安装了哪些Git客户端?也许是某个工具在做这件事?在新的克隆上是否也是如此? - Cameron Tacklind
1
你还需要重新克隆存储库以使符号链接与其一起工作。 - Aunmag
2
不需要重新克隆,修复repo的配置应该就足够了。如果在您的repo中git config core.symlinks仍然返回false,而git config --global core.symlinks则返回true,则可以使用此方法。运行git config --unset core.symlinks;注意:没有--global - lapis
在我的 Windows 10 上运行良好。非常感谢! - Lee
7
如果您不想启用开发者模式,可以将符号链接权限设置为您的帐户:按Win + R键,键入“gpedit.msc”,然后点击确定。然后导航到本地计算机策略>计算机配置> Windows设置>安全设置>本地策略>用户权限分配>创建符号链接,打开该选项并添加您的用户帐户即可。 - Honza Vojtěch
显示剩余2条评论

121

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

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

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


2
我不得不将awk替换为gawk以适应msysgit,但除此之外它完美地工作了。谢谢! - Ken Hirakawa
6
你好Ken。你介意分享一下你的脚本吗,该脚本可以检查符号链接文本文件并在Windows上使用mklink替换它们的符号链接。虽然这对我们来说实际有效,但是--assume-unchanged部分不起作用。当切换到另一个分支时,Git会提示符号链接文件已更改,需要先提交它们,而git状态则表示没有更改。你有什么想法吗? - joreg
6
这是我刚刚制作的一个PowerShell程序 - https://gist.github.com/ferventcoder/7995025 - ferventcoder
3
与其使用GNU awk来打印第四列,还有更便携的方法。例如:git ls-files -s | grep '^12' | cut -f2(第二个制表符分隔的列;其他列是空格分隔)。 - Zenexer
1
Cygwin/bash的一行代码,用于标记所有符号链接为未更改状态:for f in `git ls-files -s | awk '/120000/{print $4}'`; do git update-index --assume-unchanged $f; done - DaveAlden
显示剩余6条评论

107

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

请查看维基百科

Enter image description here


1
这对我没用。我重新安装了Windows版的git,记得勾选符号链接复选框并再次克隆我的项目。我的tslint.json文件仍然引用父目录中的文件../tslint.json。很遗憾,因为这看起来是所有提出的解决方案中最简单的一个。 - Jan Aagaard
12
你需要这样克隆它:git clone -c core.symlinks=true <URL>,在Windows上你需要以管理员权限运行。 - Leon
9
启动gpedit.msc(即组策略编辑器),将账户添加到计算机配置\Windows设置\安全设置\本地策略\用户权限分配\创建符号链接中。 - Leon
4
谢谢您的帮助,我后来意识到我的问题是我的用户属于管理员组,但这个属性对这些用户没有影响。他们需要UAC提升,而Git不提供此功能。 - ARF
11
在Windows 10创作者更新版的“开发者模式”中,不需要管理员权限。感谢 @dennis 在他的评论中提到了这一点。原文链接请见:https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/。 - Dominik
显示剩余3条评论

30

由于自从这些答案发布以来,Git已经发生了变化,因此以下是正确的说明,以便在Windows上正确使用符号链接:

2018年8月


1.确保已安装支持符号链接的Git

During the install of Git on Windows

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

(git folder)/etc/bash.bashrc

在底部添加- MSYS=winsymlinks:nativestrict

3.设置Git配置以使用符号链接

git config core.symlinks true

或者

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

注意:我已经尝试将这个设置添加到全局Git配置中,但目前它对我没有效果,因此建议将其添加到每个存储库中...

4. 拉取存储库

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

5. 重置所有符号链接(可选)

如果您有现有的存储库或使用子模块,则可能会发现符号链接未被正确地创建,因此若要刷新存储库中的所有符号链接,您可以运行以下命令。

find -type l -delete
git reset --hard

注意:这将重置自上次提交以来所做的任何更改,因此请确保您已经先提交了。


在Windows上启用开发者模式:https://gist.github.com/huenisys/1efb64e57c37cfab7054c65702588fce#file-enable-symbolic-links-for-git-on-windows-10-md - matt wilkie
在Windows上启用开发者模式:https://gist.github.com/huenisys/1efb64e57c37cfab7054c65702588fce#file-enable-symbolic-links-for-git-on-windows-10-md - matt wilkie

18

这个应该在MSysGit 中实现,但存在两个问题:

  • 符号链接仅适用于Windows Vista及更高版本(在2011年不应该成为问题,但实际上是...),因为较旧的版本只支持目录连接
  • (主要的障碍)Microsoft认为符号链接可能会造成安全风险,所以默认情况下只有管理员可以创建它们。你需要提升Git进程的权限或使用fstool在你工作的每台计算机上更改此行为。

我进行了快速搜索,发现已经在积极解决这个问题,可以看一下这个issue:224


2
更新:出于上述原因,该问题被关闭为“不予修复”。讨论表明,如果在补丁上再进行一些工作(例如仅在符号链接可用时使用它们),则可以接受修复。 - Blaisorblade
2
A.) 目前msysgit根本不支持符号链接--那么为什么不让它检测“哦,你在使用NTFS的Vista系统,让我使用符号链接”或者“哦,你在使用支持NTFS的操作系统,让我使用连接点”,或者“哦,你在使用Windows 98/FAT32,让我放弃这个功能并给你一个警告!” 然后B.) 微软的几乎所有开发工具都不能正常工作(至少不是所有功能),如果你不以管理员身份运行它们--IT中的每个人都知道开发人员需要成为他们自己电脑上的管理员。 - BrainSlugs83
1
虽然我在管理员帐户中运行某些机器,但我不会在我的开发机器上遵循这种哲学。我总是以启用UAC的常规用户身份运行。我保持一个单独的控制台打开,用于需要提升权限的操作。至于实施这个功能,就要靠有人(比如你)自愿来实现了。msysgit开发人员并不以慈善著称... - djs
@djs 用户必须以“管理员身份运行”打开命令提示符。这几乎就像是完全以管理员用户身份运行,从而完全改变了环境。没有办法以既是用户又在管理员组中的身份运行'mklink /d'。它不会触发UAC提示。它总是失败。只有两种方法可以解决:完全以管理员用户(RunAs动词)或更改组策略的非管理员用户。连接点应该是默认设置,并且应该被所有工具识别。 “安全风险”在于Windows上的符号链接可以“重定向”SMB共享。这很痛苦和残酷。 - Andrew T Finnell
9
2016年12月发布的消息称,在Windows 10中创建符号链接不再需要管理员权限。具体内容请参考以下链接:https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/#oTepts0M8148xRoj.97 - Dennis

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

来自Windows 10中的符号链接!:

现在在Windows 10创建者更新版中,用户(具有管理员权限)可以首先启用开发人员模式,然后机器上的任何用户都可以运行mklink命令而不需要提升命令行控制台权限。

是什么推动了这个变化?符号链接的可用性和使用对于现代开发人员来说非常重要:

许多流行的开发工具(如git)和程序包管理器(如npm)在创建repo或package时会识别和保留符号链接,当那些repo或package在其他地方恢复时,符号链接也将被恢复,确保不浪费磁盘空间(和用户的时间)。

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

默认情况下未启用符号链接


3
gpedit.msc是本地计算机策略,可以通过它来配置用户权限,包括SeCreateSymbolicLink等权限。在Computer Configuration->Windows Settings->Security Settings->Local Policies->User Rights Assignment中进行配置已经成为分配用户权限的标准方式。除了来自资源工具包的ntrights.exe或PowerShell之外,没有其他方法可以实现。 - 0xC0000022L

10

我建议您不要在代码库中使用符号链接。将实际内容存储在代码库中,然后再将符号链接放在代码库之外,指向内容的位置。

例如,您正在使用代码库将站点托管在类Unix系统和Windows上进行比较。将内容存储在您的代码库中,假设为 /httpRepoContentc:\httpRepoContent,这是通过 Git、SVN 等同步的文件夹。

然后,用指向代码库中内容的符号链接替换 Web 服务器的内容文件夹(/var/wwwc:\program files\web server\www {名称并不重要,必要时进行编辑)。Web 服务器将把内容视为实际在“正确”的位置,但您可以使用源代码控制。

然而,如果需要在代码库中使用符号链接,则需要研究一些预/后提交脚本。我知道您可以使用它们来执行某些操作,例如通过格式化程序解析代码文件,因此可以将符号链接在平台之间进行转换。

如果有人知道一个学习如何为常见的源代码控制,如 SVN、Git 和 MG 编写这些脚本的好地方,请添加评论。


最终,我选择了这种方法来创建一个symlink-out文件夹,并在原始文件所在的位置创建符号链接。即使我更改了.git/config设置core.symlinks = true,另一种方法也无法正常工作。只有符号链接文件保存到了repo中,而不是数据。同时,在符号链接上有文件夹时间戳的问题,因此git bash从未看到文件何时更改了文件夹内的内容。 - Eggs
@Eggs,我猜你看到的可能是链接在repo内部,所以git保存了它,很简单。但问题在于目标位于repo之外,而git不会跟随链接到目标数据。在Linux上,你有一种类型的链接可以解决这个问题,它基本上让你拥有两个指向存储在磁盘上相同数据的路径;我有一种感觉,新的Windows现在也可以做到这一点。无论如何,我仍然认为它不会做到人们想要的。 - thecoshman
@thecoshman 这不是一个解决方案,而是一个变通方法。然而,有时这并不是一个选择。我有一个使用git-annex的存储库,所有的架构都因为符号链接而工作。 - marcelo.guedes
"MG"是什么?你是指Mercurial (hg)吗? - Peter Mortensen

8
这是一个用于转换仓库中符号链接的批处理脚本,仅适用于文件,基于Josh Lee's answer。带有一些额外检查管理员权限的脚本在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

2
当已经有如此冗长和详细的答案存在时,未经记录的答案实际上没有什么用处。 - Xennex81

8

我刚试过了Git 2.30.0(发布于2020年12月28日)。

这不是一个完整的答案,但还是有一些有用的小贴士。(请随意借鉴以供您自己回答。)

Git Wiki Entry

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

Enter image description here

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

FYI:至少有三种“链接类型”。只是为了强调本 wiki 记录的一个重要方面:我并不知道这一点,但有几种方法都在表面上“有点”类似符号链接,但技术层面上却非常不同:

  • git bash 的 "ln -s" 这只是复制文件而已。这真出乎我的意料。 (FYI:普通的 Cygwin 不会这样做。MobaXterm 也不会这样做。它们都创建了一些它们的 stat 命令实际上认为是“符号链接”的东西。)
  • cmd.exe 的内置 "mklink" 命令,带有 "/D" 参数 这将创建一个目录符号链接。(参见Microsoft 文档
  • cmd.exe 的内置 "mklink" 命令,带有 "/J" 参数。 这将创建一个目录联接,也称为软链接或重解析点。(参见Microsoft 文档

Release Notes Entry

发布说明中,也不断提到符号链接。截至 2.30.0 版本,这里仍然被列为“已知问题”:

在 Windows 10 中 1703 之前,或 Developer Mode 关闭时,克隆带符号链接的存储库需要特殊权限,因此默认情况下禁用对符号链接的支持。使用 git clone -c core.symlinks=true <URL> 启用它,详情请参见此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接