我们的开发人员混合使用基于 Windows 和 Unix 的操作系统。因此,在 Unix 机器上创建的符号链接成为 Windows 开发人员的难题。在 Windows (MSysGit) 中,符号链接将转换为文本文件,其中包含指向文件的路径。相反,我想将符号链接转换为实际的 Windows 符号链接。
我必须解决的(更新的)解决方案是:
编写一个将递归查找“符号链接”文本文件的结帐后脚本。
将它们替换为与虚拟“符号链接”具有相同名称和扩展名的 Windows 符号链接(使用 mklink)
通过在文件 .git/info/exclude 中添加条目来忽略这些 Windows 符号链接
我还没有实现这个,但我相信这是解决这个问题的可靠方法。
您认为这种方法有什么缺点(如果有的话)?这个结帐后脚本甚至可以实现吗?即,我可以递归地找出 Git 创建的虚拟“符号链接”文件吗?
更新说明
对于大多数在 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
希望有帮助!
参考:
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
祝你好运!
您可以通过查找模式为 120000
的文件来找到符号链接,可能使用以下命令:
git ls-files -s | awk '/120000/{print $4}'
替换链接后,我建议使用 git update-index --assume-unchanged
将它们标记为未更改,而不是在 .git/info/exclude
中列出它们。
git ls-files -s | grep '^12' | cut -f2
(第二个制表符分隔的列;其他列以空格分隔)
for f in `git ls-files -s | awk '/120000/{print $4}'`; do git update-index --assume-unchanged $f; done
最新版本的 Git SCM(在版本 2.11.1 上测试)允许启用符号链接。但是您必须再次使用符号链接克隆存储库 git clone -c core.symlinks=true <URL>
。您需要以管理员权限运行此命令。也可以使用 mklink 在 Windows 上创建符号链接。
查看the wiki。
https://i.stack.imgur.com/rQF1w.png
tslint.json
文件引用父目录中的文件仍包含 ../tslint.json
。可惜,因为这看起来确实是其中提出的所有解决方案中最简单的。
git clone -c core.symlinks=true <URL>
在 Windows 上,您必须以管理员权限运行它。
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 受此影响,因为它们正在等待 nodegit
将 libgit2
从 v0.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
将清除“本地”设置,使更高级别的设置生效。
git config core.symlinks
在您的存储库中仍然返回 false,而 git config --global core.symlinks
表示 true,这会有所帮助。运行git config --unset core.symlinks
;注意:没有--global
!
因此,自从发布了很多这些答案以来,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
注意:这将重置自上次提交以来的所有更改,因此请确保您已先提交
它应该在 MSysGit 中实现,但有两个缺点:
符号链接仅在 Windows Vista 和更高版本中可用(它在 2011 年应该不是问题,但它是……),因为旧版本仅支持目录连接。
(大的)微软认为符号链接存在安全风险,因此默认情况下只有管理员可以创建它们。您需要提升 Git 进程的权限或使用 fstool 在您工作的每台机器上更改此行为。
我进行了快速搜索,并且正在积极开展这方面的工作;请参阅问题 224。
简短回答:如果您可以启用开发人员模式,它们现在得到很好的支持。
现在在 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
...
我建议您不要在存储库中使用符号链接。将实际内容存储在存储库中,然后将符号链接放置在指向该内容的存储库之外。
因此,假设您正在使用存储库来比较在类 Unix 系统上托管您的网站与在 Windows 上托管您的网站。将内容存储在您的存储库中,例如 /httpRepoContent
和 c:\httpRepoContent
,这是通过 Git、SVN 等同步的文件夹。
然后,将您的 Web 服务器的内容文件夹(/var/www
和 c:\program files\web server\www
{名称无关紧要,如果必须编辑})替换为存储库中内容的符号链接。 Web 服务器将看到内容实际上位于“正确”的位置,但您可以使用源代码控制。
但是,如果您需要在存储库中使用符号链接,您将需要查看某种类似于 pre/post 提交脚本的东西。我知道您可以使用它们来做一些事情,例如通过格式化程序解析代码文件,因此应该可以在平台之间转换符号链接。
如果有人知道如何为常见的源代码控制、SVN、Git 和 MG 编写这些脚本的好地方,请添加评论。
hg
) 吗?
对于在 Windows Vista、Windows 7 或更高版本上使用 Cygwin 的用户,本机 git
命令可以创建 Windows 应用程序(例如 Android Studio)识别的“正确”符号链接。您只需将 CYGWIN
环境变量设置为包含 winsymlinks:native
或 winsymlinks:nativestrict
,如下所示:
export CYGWIN="$CYGWIN winsymlinks:native"
这样做的缺点(也是一个重要的缺点)是 Cygwin shell 必须“以管理员身份运行”才能获得创建此类符号链接所需的操作系统权限。但是,一旦创建它们,使用它们不需要特殊权限。只要其他开发人员没有在存储库中更改它们,git
就可以在正常用户权限下正常运行。
就个人而言,我只将它用于由 Windows 应用程序(即非 Cygwin)导航的符号链接,因为这增加了难度。
有关此选项的详细信息,请参阅 Stack Overflow 问题:How to make a symbolic link with Cygwin in Windows 7
winsymlinks:native
。使用“开发人员模式”,您似乎不再需要在 Windows 10 中以提升的权限运行。
export MSYS=winsymlinks:nativestrict
有帮助
我刚刚尝试使用 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
这是一个批处理脚本,用于转换存储库中的符号链接,仅适用于文件,基于 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
我一直在我的文档根目录和 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 上的 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
我们使用的一个简单技巧是连续调用 git add --all
两次。
例如,我们的 Windows 7 提交脚本调用:
git add --all
git add --all
第一次添加将链接视为文本并添加要删除的文件夹。
第二个添加正确地遍历链接并通过恢复文件撤消删除。
它不如其他一些提议的解决方案优雅,但它是对我们一些添加了符号链接的遗留环境的简单修复。
这是一个用 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
}
git add-symlink
食谱对我来说非常有价值。非常感谢。pwd
的相对路径而不是存储库根目录来创建符号链接。 coderwall.com/p/z86txw/make-symlink-on-windows-in-a-git-repo