Git 推送和拉取后,目录符号链接变为文件符号链接

5

在Windows上的Git仓库中创建的目录符号链接出现某些原因被转换为文件符号链接,一旦推送到Git并重新克隆就会发生这种情况。这将导致“目录名称无效”错误。

然而,只有当符号链接在其路径中包含多个子目录时才会发生这种情况。如果只有一个子目录,则它们将继续正常工作。此外,在Bash shell中,它们仍然正常工作。

以下是原始版本库中的列表:

05/01/2019  07:50 AM <SYMLINKD> ACN [..\..\acn\Installed]
05/01/2019  08:00 AM <SYMLINKD> ACNProxy [..\..\acnproxy\bin]
04/30/2019  01:29 PM <SYMLINKD> API [..\swupdate-2\bin]
05/01/2019  08:24 AM <SYMLINKD> AnalyticsPlugin [..\..\..\analyticsinstallerplugin]
05/01/2019  08:08 AM <SYMLINKD> Encryption [..\protocols\trunk\Encryption]
05/01/2019  08:17 AM <SYMLINKD> HelpFiles [..\helpwwb6]
05/01/2019  08:34 AM <SYMLINKD> PrePackagedDatabase [..\wwb6database]
05/01/2019  09:34 AM <SYMLINKD> ToastNotifications [..\toastnotifications]
05/01/2019  08:01 AM <SYMLINKD> acnComponent [..\..\..\acn_component]
05/01/2019  07:45 AM <SYMLINKD> dante_lic_mac [..\dante_mac_fix\WWB_compressed_lic_info_files]
05/01/2019  08:05 AM <SYMLINKD> devCategory [..\..\..\devicedescriptionfiles\devCategory]
05/01/2019  08:10 AM <SYMLINKD> shared [..\..\frequencycompat\FrequencyCompatibilityCalculator]
05/01/2019  09:26 AM <SYMLINKD> shared [..\..\swupdate\src\shared]
05/01/2019  08:06 AM <SYMLINKD> skuConversion [..\..\..\skuconversion\src]

在将符号链接推送到远程Git服务器并重新克隆存储库后,那些指向具有多个子目录的路径的符号链接被更改为文件符号链接。
05/01/2019  09:28 PM <SYMLINK>  ACN [..\..\acn\Installed]
05/01/2019  09:28 PM <SYMLINK>  ACNProxy [..\..\acnproxy\bin]
05/01/2019  09:28 PM <SYMLINK>  API [..\swupdate-2\bin]
05/01/2019  09:28 PM <SYMLINKD> AnalyticsPlugin [..\..\..\analyticsinstallerplugin]
05/01/2019  09:28 PM <SYMLINK>  Encryption [..\protocols\trunk\Encryption]
05/01/2019  09:28 PM <SYMLINKD> HelpFiles [..\helpwwb6]
05/01/2019  09:29 PM <SYMLINKD> PrePackagedDatabase [..\wwb6database]
05/01/2019  09:28 PM <SYMLINKD> ToastNotifications [..\toastnotifications]
05/01/2019  09:28 PM <SYMLINKD> acnComponent [..\..\..\acn_component]
05/01/2019  09:28 PM <SYMLINK>  dante_lic_mac [..\dante_mac_fix\WWB_compressed_lic_info_files]
05/01/2019  09:28 PM <SYMLINK>  devCategory [..\..\..\devicedescriptionfiles\devCategory]
05/01/2019  09:28 PM <SYMLINK>  shared [..\..\frequencycompat\FrequencyCompatibilityCalculator]
05/01/2019  09:28 PM <SYMLINK>  shared [..\..\swupdate\src\shared]
05/01/2019  09:28 PM <SYMLINK>  skuConversion [..\..\..\skuconversion\src]

有人能解释一下这个行为吗?

在Bash shell中,所有符号链接在原始repo和克隆repo中看起来都是相同的(并且功能相同):

lrwxrwxrwx 1 ******* 1049089 17 May  1 21:28 ./wwb6/API -> ../swupdate-2/bin
lrwxrwxrwx 1 ******* 1049089 46 May  1 21:28 ./wwb6/dante_lic_mac -> ../dante_mac_fix/WWB_compressed_lic_info_files
lrwxrwxrwx 1 ******* 1049089 19 May  1 21:28 ./wwb6/datastorage/ACN -> ../../acn/Installed
lrwxrwxrwx 1 ******* 1049089 18 May  1 21:28 ./wwb6/datastorage/ACNProxy -> ../../acnproxy/bin
lrwxrwxrwx 1 ******* 1049089 22 May  1 21:28 ./wwb6/datastorage/libdatastorage/acnComponent -> ../../../acn_component
lrwxrwxrwx 1 ******* 1049089 43 May  1 21:28 ./wwb6/datastorage/libdatastorage/devCategory -> ../../../devicedescriptionfiles/devCategory
lrwxrwxrwx 1 ******* 1049089 26 May  1 21:28 ./wwb6/datastorage/libdatastorage/skuConversion -> ../../../skuconversion/src
lrwxrwxrwx 1 ******* 1049089 29 May  1 21:28 ./wwb6/Encryption -> ../protocols/trunk/Encryption
lrwxrwxrwx 1 ******* 1049089 54 May  1 21:28 ./wwb6/FrequencyCompatibility/shared -> ../../frequencycompat/FrequencyCompatibilityCalculator
lrwxrwxrwx 1 ******* 1049089 11 May  1 21:28 ./wwb6/HelpFiles -> ../helpwwb6
lrwxrwxrwx 1 ******* 1049089 33 May  1 21:28 ./wwb6/Installation/Mac/AnalyticsPlugin -> ../../../analyticsinstallerplugin
lrwxrwxrwx 1 ******* 1049089 15 May  1 21:29 ./wwb6/PrePackagedDatabase -> ../wwb6database
lrwxrwxrwx 1 ******* 1049089 25 May  1 21:28 ./wwb6/SWUpdate/shared -> ../../swupdate/src/shared
lrwxrwxrwx 1 ******* 1049089 21 May  1 21:28 ./wwb6/ToastNotifications -> ../toastnotifications

请注意,所有这些操作是在Windows10机器上完成的。但是,远程仓库位于Linux服务器上。我故意不在Windows机器上拥有管理员权限,因为开发人员也没有这些权限,并且符号链接应该对他们起作用。
为了使符号链接在Windows中工作,我执行了以下操作:
  • 在安装Git Bash时启用符号链接支持;
  • 将以下条目添加到用户的.bash_profile文件中:
  • export MSYS=winsymlinks:nativestrict

    export CYGWIN=winsymlinks:nativestrict

  • 在Git中启用符号链接支持:
  • git config --global core.symlinks true

  • 通过使用组策略编辑器将用户添加到创建符号链接策略中,分配SeCreateSymbolicLinkPrivilege权限;
  • 确保允许用户评估本地到本地符号链接:
  • fsutil behavior query symlinkevaluation

    当这种情况不存在时,作为管理员运行以下命令:

    fsutil behavior set symlinkevaluation L2L:1

  • 为了保险起见,在git clone命令中包含-c core.symlinks=true开关。
做完所有这些更改后,在Windows中创建和遍历目录符号链接可以正常工作,而不需要用户处于本地管理员组。直到它们被推送到Linux并重新下载为止。
更新: 克隆后类型从SYMLINKD变为SYMLINK的符号链接指向子模块内部的目录。子模块的根目录在容器项目克隆时创建,但内容要在容器项目(符号链接所在的位置)克隆完成之后才能拉取下来:
git clone --recursive -c core.symlinks=true ssh://<server>:7999/<repo>

当目标路径不存在时,Windows似乎不会重新创建目录符号链接,而是会创建文件符号链接。但是在Windows命令行中(就像在Linux中一样),这种方法是可行的:

mklink /d symlink ..\<some non-existing directory>\<another non-existing directory>

...运行良好。

我的当前解决办法是简单地将它们删除并恢复:

$ find . -type l -delete
$ git checkout .
Updated 14 paths from the index

尽管如此,我仍希望能够解决这个问题。


Git只存储一种符号链接,即“the”符号链接。Git假定这对于文件或目录已经足够,并且系统上只有一种符号链接。 - torek
1个回答

5

这似乎是一个未解决的问题,报告在git-for-windows/git issue 1027中。

创建了无法使用的SYMLINK。
即使稍后创建目标目录,从Windows资源管理器访问符号链接也无法使用。

更准确的问题在 git-for-windows/git issue 1646 中已被认为已在2.17+版本中得到解决。
然而,用户Jozef又创建了一个新的问题:git-for-windows/git issue 2177

维护者 Johannes Schindelin (github.com/dscho) 刚刚添加:

Git's internal data model unfortunately has a very Unix-centric view of symbolic links.
In Git for Windows, we work around that by trying to determine the type from the target (if it exists). That heuristic breaks in your case.

However, we recently introduced the feature where you can declare the symlink type in the .gitattributes: simply add a line to that file (or create that file with this line as contents if it does not yet exist):

my_symlink_name symlink=dir

Of course, you will want to add and commit this file.

I was modeling the .gitattributes line after this information:

mklink /d symlink ..<some non-existing directory><another non-existing directory>

The first column in .gitattributes is always a file name or file name pattern

楼主确认:

这在运行Git 2.21的Windows 10上表现出色(必须创建5个.gitattributes文件)
在运行Git 2.17的Windows 7上无法正常工作。

Johannes指出,可以参考Git for Windows v2.19.1(2018年10月5日)

现在可以通过.gitattributes来指定要创建的符号链接的类型(目录或文件)。

请参见请求1897

请查看提交25a7f44

Symlinks:

On Windows, symbolic links have a type: a "file symlink" must point at a file, and a "directory symlink" must point at a directory. If the type of symlink does not match its target, it doesn't work.

Git does not record the type of symlink in the index or in a tree.
On checkout it'll guess the type, which only works if the target exists at the time the symlink is created. This may often not be the case, for example when the link points at a directory inside a submodule.

The symlink attribute allows you to explicitly set the type of symlink to file or dir, so Git doesn't have to guess.

If you have a set of symlinks that point at other files, you can do:

------------------------
*.gif   symlink=file
------------------------

To tell Git that a symlink points at a directory, use:

------------------------
tools_folder    symlink=dir
------------------------

The symlink attribute is ignored on platforms other than Windows, since they don't distinguish between different types of symlinks.


我的问题与此不同:符号链接在初始创建时工作正常,目标也存在。但是在克隆后它们会从SYMLINKD更改为SYMLINK(仅当目标路径包含多个目录时)。 - Jozef
1
如果您能在多台运行最新版 Git 的 Windows 10 计算机上复现此问题,那么将其报告为单独的问题是值得的。请注意,这是已经翻译过的文本。 - VonC
1
@Jozef 谢谢。我已经编辑了答案以涉及这些问题。 - VonC
1
@Jozef 我已经编辑了答案,包括Johannes在GitHub问题中提到的.gitattributes提示。 - VonC
@Jozef 好的。就像你所看到的一样,我会关注那个 GitHub 问题 ;) - VonC
显示剩余2条评论

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