Git如何处理符号链接?


1606

如果我有一个符号链接文件或目录,并将其提交到Git存储库,那会发生什么?

我认为它将保留为符号链接,直到文件被删除为止,然后,如果您从旧版本中拉回文件,它只会创建一个普通文件。

删除文件引用时该怎么办?它只是提交悬空的链接吗?


19
.gitignore将符号链接视为文件而不是文件夹。
0xcaff 2014年

6
好吧,显然这个问题比答案要暗示的要多。例如,我想知道以下问题:如果我在存储库中创建到该存储库中某个大文件的符号链接,将更改推送到其他计算机,然后将这些更改拉到另一台计算机,将会发生什么?大文件会在两个位置上存储为大文件吗,还是会保留sym链接,例如在新计算机上,链接文件指向原始大文件?
jvriesem 2014年

7
这是一个旧线程,但是此注释可能仍然有用。响应jviesem,软链接基本上是一个文件,并带有另一个文件的名称。因此,一旦将其拉到另一台计算机上,该链接将被下载,并且将具有原始文件系统上大文件的名称。如果在新计算机上名称无效,则链接将具有无效名称。大文件将不会下载到新计算机上。
lasaro

6
@lasaro,避免git repo中的链接断开的方法是在建立符号链接时始终使用相对路径,并../..根据需要使用。
通配符

8
请注意,在大多数Windows版本中,您需要提升的权限才能创建符号链接。如果您使用Windows并git pull创建文件而不是符号链接,请尝试以管理员身份运行Git客户端。
axmrnv

Answers:


1347

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

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

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


328
顺便说一句。如果您使用的文件系统如FAT,不支持符号链接,而您的存储库使用它们,则可以将core.symlinks配置变量设置为false,符号链接将作为包含链接文本的小型纯文本文件检出。
JakubNarębski09年

14
@JakubNarębski我以前看过这个。我们的存储库中有一个文本文件,只有一行,这是我们使用的库的路径。无法弄清楚它的目的是什么。我现在知道发生了什么。
Matt K

25
我不愿对高度评价的答案发表评论,但我认为“就像普通文件一样”的措词可能会误导新用户。
马修·汉尼根

10
(用完了编辑时间)就像普通文件一样,只是内容位于Blob中。关键区别在于,对于普通文件,blob是文件内容,而对于符号链接,blob具有其链接到的文件的路径名。@JakubNarębski关于“小型纯文本文件” ..您希望它们很小并且是文本,但是blob当然是blob,并且可能是巨大的二进制文件。有关将文件错误键入为符号链接的信息,请参见stackoverflow.com/questions/18411200/…
马修·汉尼根

2
确保检查符号链接的全局设置和符号链接的本地设置。如果设置是从TortiseGit或Windows复制过来的,那么您可能会symlinks = false搞砸它们。
phyatt

250

您可以通过将文件添加到索引中来查看Git对文件的处理方式。索引就像一个预先提交。提交索引后,您可以git checkout用来将索引中的所有内容都带回到工作目录中。那么,当您向索引添加符号链接时,Git会做什么?

为了找出答案,首先建立一个符号链接:

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

Git尚不知道此文件。git ls-files使您可以检查索引(-s类似打印stat的输出):

$ git ls-files -s ./symlink
[nothing]

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

$ git add ./symlink

那么,增加了什么呢?

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

哈希是对在Git对象存储中创建的打包对象的引用。如果您在.git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c存储库的根目录中查找,则可以检查该对象。这是Git存储在资源库中的文件,您以后可以检出。如果检查此文件,您会发现它很小。它不存储链接文件的内容。

(请注意120000ls-files输出中列出了该模式。这类似于100644常规文件。)

但是,当您从存储库中检出该对象并进入文件系统时,Git对该对象有什么作用?这取决于core.symlinks配置。来自man git-config

核心符号链接

如果为false,则将符号链接检出为包含链接文本的小型纯文件。

因此,在存储库中使用符号链接时,在结帐时,您将获得一个参考完整文件系统路径的文本文件,或者是一个正确的符号链接,具体取决于core.symlinks配置的值。

无论哪种方式,符号链接引用的数据都不会存储在资源库中。


1
了不起的答案
CervEd

147

“编者注”:该帖子可能包含过时的信息。请参阅注释和有关自1.6.1起的Git更改的问题

链接目录:

重要的是要注意当目录为软链接时会发生什么。任何带有更新的Git拉动都将删除该链接并将其设置为普通目录。这是我努力学习的方法。这里这里有一些见解

之前

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

git add/commit/push

It remains the same

git pullAND 之后发现一些更新

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

4
值得一提的是关于符号链接目录的这些警告并不适用于版本的符号链接。所讨论的主要优势是人们将部分或全部工作树符号链接到不同的路径(例如到具有更多磁盘空间的不同分区上),并期望git通过现有的符号链接检出代码。也就是说,如果您的项目包含到文件或目录的版本化符号链接,则正常的symlink-as-blob行为将保留符号链接,对这些符号链接进行正确的版本更改,否则将按预期工作。
约翰·惠特利2009年

以上行为用git 1.6.5.6测试;但是我强烈怀疑版本控制行为在git中是正确的。
约翰·惠特利

22
此行为在所有版本的git上都存在还是已解决?
jbotnik 2011年

24
看来此行为已得到解决,请参见:stackoverflow.com/a/1943656/1334781
罗恩·沃特伦

2
Shekar:您会编辑答案以反映近年来git的变化吗?
einpoklum
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.