ChatGPT解决这个技术问题 Extra ChatGPT

Windows 中的 Git 符号链接

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

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

编写一个将递归查找“符号链接”文本文件的结帐后脚本。

将它们替换为与虚拟“符号链接”具有相同名称和扩展名的 Windows 符号链接(使用 mklink)

通过在文件 .git/info/exclude 中添加条目来忽略这些 Windows 符号链接

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

您认为这种方法有什么缺点(如果有的话)?这个结帐后脚本甚至可以实现吗?即,我可以递归地找出 Git 创建的虚拟“符号链接”文件吗?

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

S
Stabledog

更新说明

对于大多数在 Windows 上为符号链接和 git 以及与 *nix 系统共享存储库的问题而苦苦挣扎的 Windows 开发人员来说,这个主题是一个已解决的问题——只要您稍微更新一下 Windows 对 mklink 的理解并打开开发人员模式.

在深入了解以下深入的 git hacks 讨论之前,请参阅此 more modern answer

旧系统:

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

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

问:“如果有的话,你认为这种方法有什么缺点?”答:建议的解决方案确实有一些缺点,主要是关于存储库污染的可能性增加,或者在它们处于“Windows 符号链接”状态时意外添加了重复文件。 (更多关于这在下面的“限制”下。)

问:“这个结帐后脚本甚至可以实现吗?即我可以递归地找出 git 创建的虚拟“符号链接”文件吗?”答:是的,可以执行结帐后脚本!也许不是作为文字后 git 结帐步骤,但下面的解决方案已经很好地满足了我的需求,因此不需要文字后结帐脚本。

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

解决方案:

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

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

在 Windows 上创建 git 符号链接 git config --global alias.add-symlink '!'"$(cat <<'ETX' __git_add_symlink() { if [ $# -ne 2 ] || [ "$1" = "-h" ]; 然后 printf '%b\n' \ '用法:git add-symlink \n' \ '在 Windows 主机的 git 存储库中创建符号链接。\n' \ '注意:源必须是相对于目标位置的路径' [ "$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 " ]; 然后 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}" ]; 然后 printf 'error: git-add-symlink: %s:没有这样的文件或目录\ n' \ "${target_dir}/${source_file_or_dir}" >&2 printf '(源必须是相对于目标位置的路径!)\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 ,其中与源文件或目录对应的参数必须采用相对于目标符号链接的路径的形式.您可以像通常使用 ln 一样使用此别名。例如,存储库树:dir/dir/foo/dir/foo/bar/dir/foo/bar/baz(包含“I am baz”的文件)dir/foo/bar/lnk_file(指向../../的符号链接../file) 文件(包含“我是文件”的文件)lnk_bar(指向 dir/foo/bar/ 的符号链接) 可以在 Windows 上按如下方式创建: git init mkdir -p dir/foo/bar/ echo "I am baz " > dir/foo/bar/baz echo "我是文件" > file git add -A git commit -m "添加文件" git add-symlink ../../../file dir/foo/bar/lnk_file git add-symlink dir/foo/bar/ lnk_bar git commit -m "Add symlinks" 用 NTFS hardlinks+junctions 替换 git symlinks git config --global alias.rm-symlinks '!'"$(cat <<'ETX' __git_rm_symlinks () { case "$1" in (-h) printf '用法: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"在 (*/*) symdir=${symlink%/*} ;; (*) symdir=. ;; esac git checkout -- "$symlink" src="${symdir}/$(cat "$symlink") " posix_to_dos_se d='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" ];然后 rm -f "$symlink" cmd //C mklink //H "$doslnk" "$dossrc" elif [ -d "$src" ];然后 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" 完成 | 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' # 用于向后兼容。用法:git rm-symlinks [symlink] [symlink ] [...] 这个别名可以一举删除 git 符号链接一个接一个或一次全部删除。符号链接将替换为 NTFS 硬链接(在文件的情况下)或 NTFS 连接(在目录)。使用硬链接+连接而不是“真正的”NTFS 符号链接的好处是不需要提升的 UAC 权限来创建它们。要从子模块中删除符号链接,只需使用 git 的内置支持来迭代它们: git submodule foreach --recursive git rm-symlinks 但是,对于像这样的每一个激烈的动作,逆转是很好的......在 Windows 上恢复 git symlinks 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-文件-s | grep -E '^120000' |切-f2 ;; (*) printf '%s\n' "$@" ;;经社理事会|而 IFS= 读取 -r 符号链接; do git update-index --no-assume-unchanged "$symlink" rmdir "$symlink" >/dev/null 2>&1 git checkout -- "$symlink" printf '恢复的 git 符号链接:%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 限制:路径中带有空格的目录/文件/符号链接应该可以工作。但是制表符或换行符?YMMV ......(我的意思是:不要那样做,因为它不起作用。)如果你自己或其他人之前忘记 git checkout-symlinks做一些可能会产生广泛影响的事情,比如 git add -A,本地存储库可能最终处于污染状态。使用我们之前的“示例 repo”:echo "I am nuthafile" > dir/foo/bar/nuthaf ile echo "Updating file" >> file git add -A git status # On branch master # Changes to be commit: # (use "git reset HEAD ..." to unstage) # # new file: dir/foo /bar/nuthafile # 已修改:文件 # 已删除:lnk_bar # POLLUTION # 新文件:lnk_bar/baz # POLLUTION # 新文件:lnk_bar/lnk_file # POLLUTION # 新文件: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

祝你好运!


这是一个伟大而美妙的脚本,但是有什么理由为什么它应该在我用 git add-symlink 创建的一些文件的末尾随机附加“git”这个词?
此外,如果您的文件名包含“-h”,您将得到使用。仍然非常有用的脚本!
您的 git add-symlink 食谱对我来说非常有价值。非常感谢。
感谢分享,我只是想出了一个受此启发的脚本,它可以使用 pwd 的相对路径而不是存储库根目录来创建符号链接。 coderwall.com/p/z86txw/make-symlink-on-windows-in-a-git-repo
有没有办法使用钩子自动执行这些脚本?
J
Josh Lee

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

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

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


对于 msysgit,我不得不用 gawk 替换 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
P
Peter Mortensen

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

查看the wiki

https://i.stack.imgur.com/rQF1w.png


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

2020+ TL;DR 答案

在 Windows 10/11 中启用“开发人员模式”——给予 mklink 权限确保在 git 中启用符号链接(至少)使用系统设置之一:安装 msysgit 全局设置时选中复选框:git config --global core.symlinks true Local设置: git config core.symlinks true

小心,Windows 上 git 中对符号链接的支持是相对新的。有一些 bug 仍然会影响一些 git 客户端。值得注意的是,由于 (fixed) regression in libgit2,具有相对 (..) 路径的符号链接在某些程序中会被破坏。例如,GitKraken 受此影响,因为它们正在等待 nodegitlibgit2v0.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 将向您显示设置设置的级别 (又名“范围”),其中配置文件 (又名“origin”) 正在持久化它,并且设置的当前值。 “本地”配置很可能会覆盖“全局”或“系统”设置。 git config --unset core.symlinks 将清除“本地”设置,使更高级别的设置生效。


我所有的本地存储库都有 core.symlinks=false 这将覆盖您的解决方案。知道是什么自动生成了这个本地配置吗?可能在不选中复选框的情况下安装适用于 Windows 的 Git?
@gravidThoughts 您安装了哪些 git 客户端?也许一些工具正在这样做?这在新克隆上是真的吗?
此外,您必须重新克隆存储库以使符号链接与它一起使用
谢谢@Aunmag 重新克隆成功了。 “切换分支将强制重新创建丢失的符号链接。”没用。
无需重新克隆,修复 repo 的 配置就足够了。如果 git config core.symlinks 在您的存储库中仍然返回 false,而 git config --global core.symlinks 表示 true,这会有所帮助。运行git config --unset core.symlinks;注意:没有--global
P
Peter Mortensen

因此,自从发布了很多这些答案以来,Git 的情况发生了变化,以下是使符号链接在 Windows 中正常工作的正确说明:

2018 年 8 月

1. 确保安装了带有符号链接支持的 Git

https://i.stack.imgur.com/Am9L1.png

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 配置中,但目前它对我不起作用,所以我建议将它添加到每个存储库中......

4.拉取仓库

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

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

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

find -type l -delete
git reset --hard

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


P
Peter Mortensen

它应该在 MSysGit 中实现,但有两个缺点:

符号链接仅在 Windows Vista 和更高版本中可用(它在 2011 年应该不是问题,但它是……),因为旧版本仅支持目录连接。

(大的)微软认为符号链接存在安全风险,因此默认情况下只有管理员可以创建它们。您需要提升 Git 进程的权限或使用 fstool 在您工作的每台机器上更改此行为。

我进行了快速搜索,并且正在积极开展这方面的工作;请参阅问题 224


更新:由于上述原因,该问题已作为 wontfix 关闭。讨论表明,可以通过对补丁进行更多工作来接受修复(例如,仅当它们工作时才使用符号链接)。
A.) 目前 msysgit 根本不支持符号链接——那么为什么不让它检测“哦,你在使用 NTFS 的 vista 让我使用符号链接”或“哦,你在一个支持与 NTFS 的连接的操作系统上,让我使用这些”,或者“哦,你在 Windows 98/fat32 上,让我回退到没有这个功能,而是给你一个警告!”然后 B.) 几乎所有微软的开发人员。如果您不以管理员身份运行工具,工具将无法正常工作(至少对于它们的所有功能而言)——IT 中的每个人都知道,开发人员需要在自己的机器上成为管理员。
虽然我确实在管理员帐户中运行某些机器,但我并没有在我的开发机器上遵循这种理念。我总是以启用 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/…
P
Peter Mortensen

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

来自 Symlinks in Windows 10!

现在在 Windows 10 Creators Update 中,用户(具有管理员权限)可以先启用开发者模式,然后机器上的任何用户都可以运行 mklink 命令,而无需提升命令行控制台。是什么推动了这种变化?符号链接的可用性和使用对现代开发人员来说是一件大事:许多流行的开发工具(如 git)和包管理器(如 npm)分别在创建存储库或包时识别并保留符号链接。当这些存储库或程序包在其他地方恢复时,符号链接也会恢复,确保不会浪费磁盘空间(和用户的时间)。

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

https://i.stack.imgur.com/1LKsG.png


gpedit.msc -> Local Computer Policy -> Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment 长期以来一直是分配 SeCreateSymbolicLink 和朋友等用户权限的规范方式。除了来自 Resource Kit 或 PowerShell 的 ntrights.exe ...
P
Peter Mortensen

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

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

然后,将您的 Web 服务器的内容文件夹(/var/wwwc:\program files\web server\www {名称无关紧要,如果必须编辑})替换为存储库中内容的符号链接。 Web 服务器将看到内容实际上位于“正确”的位置,但您可以使用源代码控制。

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

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


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

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

export CYGWIN="$CYGWIN winsymlinks:native"

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

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

有关此选项的详细信息,请参阅 Stack Overflow 问题:How to make a symbolic link with Cygwin in Windows 7


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

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

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

Git 维基条目

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

https://i.stack.imgur.com/kZmPI.png

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

仅供参考:至少有三种“链接”。并且只是为了强调这个 wiki 条目的一个重要方面:我不知道这一点,但有几种方式,所有这些方式表面上都是“某种”符号链接,但在技术层面上却大不相同:

git bash 的 "ln -s" 只是复制东西。好家伙。这出乎我的意料。 (仅供参考:Plain Cygwin 不这样做。Mobaxterm 不这样做。相反,它们都创建了它们的 stat 命令实际上识别为“符号链接”的东西。)

cmd.exe 带有“/D”参数的内置“mklink”命令创建目录符号链接。 (请参阅 Microsoft 文档)

cmd.exe 带有“/J”参数的内置“mklink”命令。它创建了一个目录连接 AKA 软链接 AKA 重解析点。 (请参阅 Microsoft 文档。)

发行说明条目

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

在 1703 之前的 Windows 10 上,或关闭开发人员模式时,使用符号链接克隆存储库时需要特殊权限,因此默认情况下禁用对符号链接的支持。使用 git clone -c core.symlinks=true 来启用它,详情请看这里。


P
Peter Mortensen

这是一个批处理脚本,用于转换存储库中的符号链接,仅适用于文件,基于 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

当已经存在如此冗长和冗长的答案时,未记录的答案实际上并没有多大用处。
P
Peter Mortensen

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

>mklink /j <location(path) of link> <source of link>

例如:

>mklink /j c:\gitRepos\Posts C:\Bitnami\wamp\apache2\htdocs\Posts


小心使用 Windows 资源管理器和连接;它不区分连接点和基本位置,删除将递归到目标并删除它的内容,而删除符号链接只会删除符号链接。只是粗心的人的陷阱。
实际上,刚刚在最新的 Windows7 上对此进行了测试,但它不再这样做了,因此在过去几年的某个时候,连接点的处理已经得到了改进。
P
Peter Mortensen

我一直在寻找一种简单的解决方案来处理 Windows 上的 Unix 符号链接。非常感谢您在以前的答案中使用 Git 别名。

可以对 rm-symbolic 链接进行一点优化,这样它就不会删除目标文件夹中的文件,以防别名被意外运行第二次。请观察循环中的新 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

P
Peter Mortensen

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

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

git add --all
git add --all

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

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

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


P
Peter Mortensen

这是一个用 Windows 替换 Unix 符号链接的 PowerShell 脚本。

# This fixes permission denied errors you might get when
# there are Git symbolic links 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 without
# committing on OS X, 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.
#
# NOTE: It must be run in elevated PowerShell

$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
}