Windows中的Git符号链接

Windows中的Git符号链接

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

[医]更新)我必须解决的办法是:

  • 编写一个签出后脚本,递归地查找“symlink”文本文件。
  • 将它们替换为windows符号链接(使用mklink),其名称和扩展名与虚拟“符号链接”相同。
  • 通过在.git/info/EXECUTE中添加条目来忽略这些windows符号链接

我没有落实这一点,但我认为这是解决这一问题的坚实办法。

问题:

  1. 如果有的话,你认为这种方法有什么坏处?
  2. 这个结帐后脚本可以实现吗?也就是说,我能递归地找到虚拟的“符号链接”文件git创建的吗?
  3. 有没有人写过这样的剧本?


潇湘沐
浏览 859回答 3
3回答

拉丁的传说

您可以通过查找具有120000,可能使用以下命令:git ls-files -s | awk '/120000/{print $4}'一旦您替换了链接,我建议将它们标记为git update-index --assume-unchanged,而不是将它们列在.git/info/exclude.

紫衣仙女

我刚才问了一个完全相同的问题(一般不是在这里),最后提出了一个与OP的建议非常相似的解决方案。首先,我将直接回答问题1,2和3,然后我将张贴我最后使用的解决方案。建议的解决方案确实有一些缺点,主要是因为存储库污染的可能性增加,或者在文件处于“Windows符号链接”状态时不小心添加重复文件。(下文“限制”一节将对此作更多介绍。)是的,结帐后脚本是可实现的!也许不是作为一个字面上的帖子-git checkout步骤,但是下面的解决方案已经很好地满足了我的需求,所以不需要一个文字的签出脚本。是!解决办法:我们的开发人员所处的情况与OP的大致相同:Windows和类Unix的主机、存储库和子模块混合在一起,有许多git符号链接,并且在MsysGit的发布版本中没有本地支持(尚未)来智能地在Windows主机上处理这些符号链接。感谢josh lee指出git与特殊的filemode提交了符号链接。120000..有了这些信息,就可以添加一些git别名,允许在Windows主机上创建和操作git符号链接。在Windows上创建Git符号链接git&nbsp;config&nbsp;--global&nbsp;alias.add-symlink&nbsp;'!'"$(cat&nbsp;<<'ETX' __git_add_symlink()&nbsp;{ &nbsp;&nbsp;if&nbsp;[&nbsp;$#&nbsp;-ne&nbsp;2&nbsp;]&nbsp;||&nbsp;[&nbsp;"$1"&nbsp;=&nbsp;"-h"&nbsp;];&nbsp;then &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'%b\n'&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'usage:&nbsp;git&nbsp;add-symlink&nbsp;<source_file_or_dir>&nbsp;<target_symlink>\n'&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Create&nbsp;a&nbsp;symlink&nbsp;in&nbsp;a&nbsp;git&nbsp;repository&nbsp;on&nbsp;a&nbsp;Windows&nbsp;host.\n'&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Note:&nbsp;source&nbsp;MUST&nbsp;be&nbsp;a&nbsp;path&nbsp;relative&nbsp;to&nbsp;the&nbsp;location&nbsp;of&nbsp;target' &nbsp;&nbsp;&nbsp;&nbsp;[&nbsp;"$1"&nbsp;=&nbsp;"-h"&nbsp;]&nbsp;&&&nbsp;return&nbsp;0&nbsp;||&nbsp;return&nbsp;2 &nbsp;&nbsp;fi &nbsp;&nbsp;source_file_or_dir=${1#./} &nbsp;&nbsp;source_file_or_dir=${source_file_or_dir%/} &nbsp;&nbsp;target_symlink=${2#./} &nbsp;&nbsp;target_symlink=${target_symlink%/} &nbsp;&nbsp;target_symlink="${GIT_PREFIX}${target_symlink}" &nbsp;&nbsp;target_symlink=${target_symlink%/.} &nbsp;&nbsp;:&nbsp;"${target_symlink:=.}" &nbsp;&nbsp;if&nbsp;[&nbsp;-d&nbsp;"$target_symlink"&nbsp;];&nbsp;then &nbsp;&nbsp;&nbsp;&nbsp;target_symlink="${target_symlink%/}/${source_file_or_dir##*/}" &nbsp;&nbsp;fi &nbsp;&nbsp;case&nbsp;"$target_symlink"&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;(*/*)&nbsp;target_dir=${target_symlink%/*}&nbsp;;; &nbsp;&nbsp;&nbsp;&nbsp;(*)&nbsp;target_dir=$GIT_PREFIX&nbsp;;; &nbsp;&nbsp;esac &nbsp;&nbsp;target_dir=$(cd&nbsp;"$target_dir"&nbsp;&&&nbsp;pwd) &nbsp;&nbsp;if&nbsp;[&nbsp;!&nbsp;-e&nbsp;"${target_dir}/${source_file_or_dir}"&nbsp;];&nbsp;then &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'error:&nbsp;git-add-symlink:&nbsp;%s:&nbsp;No&nbsp;such&nbsp;file&nbsp;or&nbsp;directory\n'&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"${target_dir}/${source_file_or_dir}"&nbsp;>&2 &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'(Source&nbsp;MUST&nbsp;be&nbsp;a&nbsp;path&nbsp;relative&nbsp;to&nbsp;the&nbsp;location&nbsp;of&nbsp;target!)\n'&nbsp;>&2 &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;2 &nbsp;&nbsp;fi &nbsp;&nbsp;git&nbsp;update-index&nbsp;--add&nbsp;--cacheinfo&nbsp;120000&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"$(printf&nbsp;'%s'&nbsp;"$source_file_or_dir"&nbsp;|&nbsp;git&nbsp;hash-object&nbsp;-w&nbsp;--stdin)"&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"${target_symlink}"&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;git&nbsp;checkout&nbsp;--&nbsp;"$target_symlink"&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;printf&nbsp;'%s&nbsp;->&nbsp;%s\n'&nbsp;"${target_symlink#$GIT_PREFIX}"&nbsp;"$source_file_or_dir"&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;||&nbsp;return&nbsp;$? } __git_add_symlink ETX )"用法:git add-symlink <source_file_or_dir> <target_symlink>,其中对应于源文件或目录的参数必须采用路径的形式。相对于目标符号链接。您可以按照通常使用的方式使用此别名。ln.例如,存储库树:dir/ dir/foo/ dir/foo/bar/ dir/foo/bar/baz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(file&nbsp;containing&nbsp;"I&nbsp;am&nbsp;baz") dir/foo/bar/lnk_file&nbsp;(symlink&nbsp;to&nbsp;../../../file) file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(file&nbsp;containing&nbsp;"I&nbsp;am&nbsp;file") lnk_bar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(symlink&nbsp;to&nbsp;dir/foo/bar/)可以按以下方式在Windows上创建:git&nbsp;init mkdir&nbsp;-p&nbsp;dir/foo/bar/ echo&nbsp;"I&nbsp;am&nbsp;baz"&nbsp;>&nbsp;dir/foo/bar/baz echo&nbsp;"I&nbsp;am&nbsp;file"&nbsp;>&nbsp;file git&nbsp;add&nbsp;-A git&nbsp;commit&nbsp;-m&nbsp;"Add&nbsp;files" git&nbsp;add-symlink&nbsp;../../../file&nbsp;dir/foo/bar/lnk_file git&nbsp;add-symlink&nbsp;dir/foo/bar/&nbsp;lnk_bar git&nbsp;commit&nbsp;-m&nbsp;"Add&nbsp;symlinks"用NTFS硬链+结取代git符号git&nbsp;config&nbsp;--global&nbsp;alias.rm-symlinks&nbsp;'!'"$(cat&nbsp;<<'ETX' __git_rm_symlinks()&nbsp;{ &nbsp;&nbsp;case&nbsp;"$1"&nbsp;in&nbsp;(-h) &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'usage:&nbsp;git&nbsp;rm-symlinks&nbsp;[symlink]&nbsp;[symlink]&nbsp;[...]\n' &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0 &nbsp;&nbsp;esac &nbsp;&nbsp;ppid=$$ &nbsp;&nbsp;case&nbsp;$#&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;(0)&nbsp;git&nbsp;ls-files&nbsp;-s&nbsp;|&nbsp;grep&nbsp;-E&nbsp;'^120000'&nbsp;|&nbsp;cut&nbsp;-f2&nbsp;;; &nbsp;&nbsp;&nbsp;&nbsp;(*)&nbsp;printf&nbsp;'%s\n'&nbsp;"$@"&nbsp;;; &nbsp;&nbsp;esac&nbsp;|&nbsp;while&nbsp;IFS=&nbsp;read&nbsp;-r&nbsp;symlink;&nbsp;do &nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;"$symlink"&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*/*)&nbsp;symdir=${symlink%/*}&nbsp;;; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*)&nbsp;symdir=.&nbsp;;; &nbsp;&nbsp;&nbsp;&nbsp;esac &nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;--&nbsp;"$symlink" &nbsp;&nbsp;&nbsp;&nbsp;src="${symdir}/$(cat&nbsp;"$symlink")" &nbsp;&nbsp;&nbsp;&nbsp;posix_to_dos_sed='s_^/\([A-Za-z]\)_\1:_;s_/_\\\\_g' &nbsp;&nbsp;&nbsp;&nbsp;doslnk=$(printf&nbsp;'%s\n'&nbsp;"$symlink"&nbsp;|&nbsp;sed&nbsp;"$posix_to_dos_sed") &nbsp;&nbsp;&nbsp;&nbsp;dossrc=$(printf&nbsp;'%s\n'&nbsp;"$src"&nbsp;|&nbsp;sed&nbsp;"$posix_to_dos_sed") &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;[&nbsp;-f&nbsp;"$src"&nbsp;];&nbsp;then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rm&nbsp;-f&nbsp;"$symlink" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd&nbsp;//C&nbsp;mklink&nbsp;//H&nbsp;"$doslnk"&nbsp;"$dossrc" &nbsp;&nbsp;&nbsp;&nbsp;elif&nbsp;[&nbsp;-d&nbsp;"$src"&nbsp;];&nbsp;then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rm&nbsp;-f&nbsp;"$symlink" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd&nbsp;//C&nbsp;mklink&nbsp;//J&nbsp;"$doslnk"&nbsp;"$dossrc" &nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'error:&nbsp;git-rm-symlink:&nbsp;Not&nbsp;a&nbsp;valid&nbsp;source\n'&nbsp;>&2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'%s&nbsp;=/=>&nbsp;%s&nbsp;&nbsp;(%s&nbsp;=/=>&nbsp;%s)...\n'&nbsp;\ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"$symlink"&nbsp;"$src"&nbsp;"$doslnk"&nbsp;"$dossrc"&nbsp;>&2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false &nbsp;&nbsp;&nbsp;&nbsp;fi&nbsp;||&nbsp;printf&nbsp;'ESC[%d]:&nbsp;%d\n'&nbsp;"$ppid"&nbsp;"$?" &nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;update-index&nbsp;--assume-unchanged&nbsp;"$symlink" &nbsp;&nbsp;done&nbsp;|&nbsp;awk&nbsp;' &nbsp;&nbsp;&nbsp;&nbsp;BEGIN&nbsp;{&nbsp;status_code&nbsp;=&nbsp;0&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;/^ESC\['"$ppid"'\]:&nbsp;/&nbsp;{&nbsp;status_code&nbsp;=&nbsp;$2&nbsp;;&nbsp;next&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;print&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;END&nbsp;{&nbsp;exit&nbsp;status_code&nbsp;} &nbsp;&nbsp;' } __git_rm_symlinks ETX )" git&nbsp;config&nbsp;--global&nbsp;alias.rm-symlink&nbsp;'!git&nbsp;rm-symlinks'&nbsp;&nbsp;#&nbsp;for&nbsp;back-compat.用法:git&nbsp;rm-symlinks&nbsp;[symlink]&nbsp;[symlink]&nbsp;[...]这个别名可以一次地删除git符号链接。Symlink将替换为NTFS硬链接(在文件中)或NTFS连接(在目录中)。与“真”NTFS符号链接相比,使用硬链接+连接的好处是要创建UAC权限,不需要经过提升的UAC权限。要从子模块中删除符号链接,只需使用git内置的支持迭代它们:git&nbsp;submodule&nbsp;foreach&nbsp;--recursive&nbsp;git&nbsp;rm-symlinks但是,对于每一次如此激烈的行动,有一个逆转是很好的.在Windows上恢复Git符号链接git&nbsp;config&nbsp;--global&nbsp;alias.checkout-symlinks&nbsp;'!'"$(cat&nbsp;<<'ETX' __git_checkout_symlinks()&nbsp;{ &nbsp;&nbsp;case&nbsp;"$1"&nbsp;in&nbsp;(-h) &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'usage:&nbsp;git&nbsp;checkout-symlinks&nbsp;[symlink]&nbsp;[symlink]&nbsp;[...]\n' &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0 &nbsp;&nbsp;esac &nbsp;&nbsp;case&nbsp;$#&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;(0)&nbsp;git&nbsp;ls-files&nbsp;-s&nbsp;|&nbsp;grep&nbsp;-E&nbsp;'^120000'&nbsp;|&nbsp;cut&nbsp;-f2&nbsp;;; &nbsp;&nbsp;&nbsp;&nbsp;(*)&nbsp;printf&nbsp;'%s\n'&nbsp;"$@"&nbsp;;; &nbsp;&nbsp;esac&nbsp;|&nbsp;while&nbsp;IFS=&nbsp;read&nbsp;-r&nbsp;symlink;&nbsp;do &nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;update-index&nbsp;--no-assume-unchanged&nbsp;"$symlink" &nbsp;&nbsp;&nbsp;&nbsp;rmdir&nbsp;"$symlink"&nbsp;>/dev/null&nbsp;2>&1 &nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;--&nbsp;"$symlink" &nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;'Restored&nbsp;git&nbsp;symlink:&nbsp;%s&nbsp;->&nbsp;%s\n'&nbsp;"$symlink"&nbsp;"$(cat&nbsp;"$symlink")" &nbsp;&nbsp;done } __git_checkout_symlinks ETX )" git&nbsp;config&nbsp;--global&nbsp;alias.co-symlinks&nbsp;'!git&nbsp;checkout-symlinks'用法:git checkout-symlinks [symlink] [symlink] [...],这会使git rm-symlinks,有效地将存储库恢复到其自然状态(除了您的更改之外,应保持原封不动)。对于子模块:git&nbsp;submodule&nbsp;foreach&nbsp;--recursive&nbsp;git&nbsp;checkout-symlinks限制:路径中有空格的目录/文件/符号链接应该可以工作。但是标签还是新行?YMMV…(我的意思是:不要那样做,因为它不会工作)如果你或其他人忘了git checkout-symlinks在做一些有可能造成广泛后果的事情之前git add -A,本地存储库可能会以污染状态。使用我们以前的“示例回购”:echo&nbsp;"I&nbsp;am&nbsp;nuthafile"&nbsp;>&nbsp;dir/foo/bar/nuthafile echo&nbsp;"Updating&nbsp;file"&nbsp;>>&nbsp;file git&nbsp;add&nbsp;-A git&nbsp;status #&nbsp;On&nbsp;branch&nbsp;master #&nbsp;Changes&nbsp;to&nbsp;be&nbsp;committed: #&nbsp;&nbsp;&nbsp;(use&nbsp;"git&nbsp;reset&nbsp;HEAD&nbsp;<file>..."&nbsp;to&nbsp;unstage) # #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;file:&nbsp;&nbsp;&nbsp;dir/foo/bar/nuthafile #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified:&nbsp;&nbsp;&nbsp;file #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deleted:&nbsp;&nbsp;&nbsp;&nbsp;lnk_bar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;POLLUTION #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;file:&nbsp;&nbsp;&nbsp;lnk_bar/baz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;POLLUTION #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;file:&nbsp;&nbsp;&nbsp;lnk_bar/lnk_file&nbsp;&nbsp;#&nbsp;POLLUTION #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;file:&nbsp;&nbsp;&nbsp;lnk_bar/nuthafile&nbsp;#&nbsp;POLLUTION #哇哦.。因此,在构建项目之前和之后,而不是在签出或推送之前,将这些别名作为Windows用户执行的步骤是很好的。但每一种情况都是不同的。这些别名对我来说已经足够有用了,所以不需要真正的结帐解决方案。希望能帮上忙!参考资料:http:/git-scm.com/book/en/git-inals-Git-Objectshttp:/Technnet.microsoft.com/en-us/Library/cc753194POSIX的遵守情况(嗯,除了那些mklink当然)巴什主义!支持包含空格的目录和文件。零和非零退出状态代码(分别用于通信请求的命令的成功/失败)现在被正确保存/返回。这个add-symlink别名现在更像Ln(1)并且可以在存储库中的任何目录中使用,而不仅仅是存储库的根目录。这个rm-symlink别名(单数)已被rm-symlinks别名(复数),它现在接受多个参数(或者根本不接受参数,它像以前一样在存储库中查找所有的符号链接),用于选择性地将git符号链接转换为NTFS硬链接+连接。这个checkout-symlinks别名还被更新为接受多个参数(或根本不接受,=All),以选择性地逆转上述转换。最后注:虽然我使用Bash3.2(甚至3.1)测试了加载和运行这些别名的方法,对于那些由于各种原因仍然停留在这些古老版本上的人来说,请注意,像这些版本一样古老的版本因其解析器错误而臭名昭著。如果您在尝试安装这些别名时遇到了问题,首先应该考虑的是升级shell(对于Bash,请使用CTRL+X、CTRL+V检查版本)。或者,如果您试图通过将它们粘贴到您的终端仿真器中来安装它们,您可能会更幸运地将它们粘贴到一个文件中并将其外包,例如.&nbsp;./git-win-symlinks.sh祝好运!
打开App,查看更多内容
随时随地看视频慕课网APP