题 git如何处理符号链接?


如果我有一个符号链接的文件或目录,我将它提交给git repo会发生什么?

我会假设它将它作为符号链接留下,直到文件被删除,然后如果你从旧版本拉回文件它只是创建一个普通文件。

当我删除它引用的文件时它会怎么做?它只是提交悬空链接吗?


1316
2018-06-05 06:53


起源


.gitignore 将符号链接视为文件而不是文件夹。 - 0xcaff
嗯,显然问题还有答案所暗示的问题。例如,我想知道以下内容:如果我在我的存储库中创建一个sym链接到该存储库中的某个大文件,推送更改,然后将这些更改拉到另一台机器,会发生什么?将大文件存储为两个位置的大文件,还是保留sym链接,这样在新机器上,链接文件指向原始大文件? - jvriesem
这是一个旧线程,但这个评论可能仍然有用。作为对jviesem的回应,软链接基本上是具有另一个文件名称的文件。因此,一旦将其拉到另一台机器,就会下载链接,并且它将在原始文件系统上具有大文件的名称。如果在新计算机上名称无效,则链接将具有无效名称。大文件将不会下载到新计算机。 - lasaro
@lasaro,避免git repo中断链接的方法是在制作符号链接时总是使用相对路径,使用 ../.. 如所须。 - Wildcard
请注意,在大多数Windows版本中,您需要提升权限才能创建符号链接。如果你在Windows和 git pull 创建一个文件而不是符号链接,尝试以管理员身份运行Git客户端。 - asmironov


答案:


git只是将一个链接的内容(即它链接到的文件系统对象的路径)存储在'blob'中,就像它对普通文件一样。然后,它在表示其包含目录的树对象中存储名称,模式和类型(包括它是符号链接的事实)。

签出包含链接的树时,无论目标文件系统对象是否存在,它都会将对象还原为符号链接。

如果删除符号链接引用的文件,则不会以任何方式影响git控制的符号链接。你将有一个悬空参考。用户可以根据需要删除或更改链接以指向有效的内容。


1097
2018-06-05 07:01



BTW。如果您使用的FAT文件系统不支持符号链接,并且您的存储库使用它们,则可以进行设置 core.symlinks 配置变量为false,符号链接将作为包含链接文本的小型纯文本文件签出。 - Jakub Narębski
@JakubNarębski我之前看过这个。我们的仓库中有一个文本文件,其中包含一行,即我们使用的库的路径。无法弄清楚它的目的是什么。我现在知道发生了什么。 - Matt K
我毫不犹豫地对高度赞成的答案发表评论,但我认为短语“就像普通文件一样”可能会误导新人。 - Matthew Hannigan
(用完了编辑时间)它就像一个普通的文件,只是内容是一个blob。关键区别在于,对于普通文件,blob是文件内容,但对于符号链接,blob具有链接到的文件的路径名。 @JakubNarębski关于“小纯文本文件”..你会希望它们很小而且文本,但当然blob是一个blob,可能是巨大的二进制文件。看到 stackoverflow.com/questions/18411200/... 当文件被错误输入为符号链接时。 - Matthew Hannigan
请务必检查符号链接的全局设置和符号链接的本地设置。如果设置是从TortiseGit或Windows复制的,那么你可以拥有 symlinks = false 弄乱他们。 - phyatt


TL; DR:符号链接引用的数据不存储在存储库中。


您可以通过查看将文件添加到索引时的功能来了解Git对文件执行的操作。索引就像预先提交一样。随着索引的提交,您可以使用 git checkout 将索引中的所有内容返回到工作目录中。那么,当您向索引添加符号链接时,Git会做什么?

要找出答案,首先要做一个符号链接:

$ ln -s /Path/referenced/by/symlink symlink

Git还不知道这个文件。 git ls-files 让你检查索引(-s 版画 stat式输出):

$ git ls-files -s ./symlink
$

现在,通过将符号链接的内容添加到索引,将其添加到Git对象库中。将文件添加到索引时,Git将其内容存储在Git对象库中。

$ git add ./symlink

那么,添加了什么?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink
$

哈希是对在Git对象库中创建的压缩对象的引用。如果查看,可以检查此对象 .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c

120000 是文件模式。它会是这样的 100644 对于常规文件,是链接的特殊模式。从 man git-config

core.symlinks

如果为false,则将符号链接签出为包含链接文本的小型纯文本。 git-update-index(1)和git-add(1)不会将记录的类型更改为常规文件。

使用 git cat-file -p 漂亮地打印内容:

$ git cat-file -p 1596f9db1
/Path/referenced/by/symlink

所以,这就是Git对符号链接所做的事情:当你 git checkout 在符号链接中,您要么获得一个文本文件,其中包含对完整文件系统路径的引用,要么根据配置获得符号链接。 符号链接引用的数据不存储在存储库中。


152
2017-09-13 17:06





符号链接目录:

重要的是要注意当存在软链接的目录时会发生什么。 任何带有更新的git pull都会删除该链接并使其成为普通目录。这就是我学到的难点。一些见解 这里 和 这里。

之前

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir

git add / commit / push

It remains the same

git pull之后发现了一些更新

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir

140
2017-10-02 06:16



值得注意的是这些关于符号链接目录的警告 不要 适用于版本化的符号链接。有问题的主要问题是人们将部分或全部工作树符号化为不同的路径(比如说在具有更多磁盘空间的不同分区上),并期望git通过现有的符号链接来检查代码。也就是说,如果您的项目包含文件或目录的版本化符号链接,则正常的符号链接作为blob行为将保留符号链接,正确地对这些符号链接进行版本更改,否则将按预期工作。 - John Whitley
上面的行为用git 1.6.5.6测试;但是我强烈怀疑git中的版本化行为已经有一段时间了。 - John Whitley
这种行为是出现在所有版本的git上还是已经修复了? - jbotnik
现在似乎已修复此行为,请参阅: stackoverflow.com/a/1943656/1334781 - Ron Wertlen
Shekar:你会编辑你的答案来反映近年来git的变化吗? - einpoklum