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

Joz*_*zef 5 windows git symlink

由于某种原因,在 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]
Run Code Online (Sandbox Code Playgroud)

将符号链接推送到远程 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]
Run Code Online (Sandbox Code Playgroud)

谁能解释这种行为?

在 Bash shell 中,所有符号链接在原始存储库和克隆存储库中看起来都相同(和功能):

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
Run Code Online (Sandbox Code Playgroud)

请注意,所有这些都是在 Windows 10 计算机上完成的。但是,远程存储库位于 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

  • 为了更好地衡量,包括 -c core.symlinks=true 开关到 git clone 命令。

进行所有这些更改后,创建和遍历目录符号链接在 Windows 中可以正常工作,而无需用户位于本地管理员组中。直到它们被推送到 Linux 并重新下载。

更新:克隆后,将类型从 SYMLINKD 更改为 SYMLINK 的符号链接指向子模块内的目录。克隆容器项目时会创建子模块的根目录,但直到容器项目(符号链接所在的位置)克隆完成后才会拉取内容:

git clone --recursive -c core.symlinks=true ssh://<server>:7999/<repo>
Run Code Online (Sandbox Code Playgroud)

当目标尚不存在时,Windows 似乎不会重新创建目录符号链接。它会创建文件符号链接类型的文件。不过,这确实可以在 Windows 命令行中运行(就像在 Linux 中一样):

mklink /d symlink ..\<some non-existing directory>\<another non-existing directory>
Run Code Online (Sandbox Code Playgroud)

...工作正常。

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

$ find . -type l -delete
$ git checkout .
Updated 14 paths from the index
Run Code Online (Sandbox Code Playgroud)

不过更愿意解决这个问题。

Von*_*onC 5

这似乎是一个悬而未决的问题,在git-for-windows/git issues 1027中报告

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

更准确的问题是,git-for-windows/git 问题 1646应该在 2.17+ 中得到修复。
尽管如此,OP Jozef 还是创建了一个新问题:git-for-windows/git issues 2177

维护者 Johannes Schindelin ( github.com/dscho) 刚刚补充道:

不幸的是,Git 的内部数据模型具有非常以 Unix 为中心的符号链接视图。
在 Windows 版 Git 中,我们通过尝试确定目标的类型(如果存在)来解决这个问题。这种启发式方法在你的情况下会被打破。

但是,我们最近引入了一项功能,您可以在 : 中声明符号链接类型,.gitattributes只需向该文件添加一行(或者如果该文件尚不存在,则使用该行作为内容创建该文件):

my_symlink_name symlink=dir
Run Code Online (Sandbox Code Playgroud)

当然,您需要添加并提交该文件。

我根据以下信息对线路进行建模.gitattributes

mklink /d symlink ..<some non-existing directory><another non-existing directory>
Run Code Online (Sandbox Code Playgroud)

中的.gitattributes第一列始终是文件名或文件名模式

OP 确认:

这在运行 Git 2.21 的 Windows 10 机器上效果很好(必须创建 5 个.gitattributes文件),
但在运行 Git 2.17 的 Windows 7 机器上不起作用。

Johannes 指出Git for Windows v2.19.1(2018 年 10 月 5 日)

现在可以通过.gitattributes.

请参阅提交 25a7f44

符号链接:

在 Windows 上,符号链接有一种类型:“文件符号链接”必须指向文件,“目录符号链接”必须指向目录。如果符号链接的类型与其目标不匹配,则它不起作用。

Git 不会在索引或树中记录符号链接的类型。
签出时,它会猜测类型,只有在创建符号链接时目标存在的情况下,该类型才有效。通常情况可能并非如此,例如当链接指向子模块内的目录时。

symlink属性允许您将符号链接的类型显式设置为filedir,因此 Git 不必猜测。

如果您有一组指向其他文件的符号链接,您可以执行以下操作:

------------------------
*.gif   symlink=file
------------------------
Run Code Online (Sandbox Code Playgroud)

要告诉 Git 符号链接指向目录,请使用:

------------------------
tools_folder    symlink=dir
------------------------
Run Code Online (Sandbox Code Playgroud)

symlink属性在 Windows 以外的平台上被忽略,因为它们不区分不同类型的符号链接。