Git如何处理符号链接?

时间:2009-06-05 06:53:33

标签: git version-control symlink

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

我认为它会将其作为符号链接留下,直到文件被删除,然后如果你从旧版本中取回文件,它就会创建一个普通文件。

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

4 个答案:

答案 0 :(得分:1209)

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

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

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

答案 1 :(得分:202)

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


通过查看将文件添加到索引时的功能,您可以了解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

  

core.symlinks

     

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

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

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

答案 2 :(得分:145)

  

“编辑”注意:此帖子可能包含过时的信息。有关自1.6.1以来Git中的更改,请参阅注释和this question

符号链接目录:

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

示例

之前

 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

答案 3 :(得分:0)

特殊情况:当 "git checkout"(man) 删除了它正在检查的提交中不存在的路径时,它不够小心跟踪符号链接,这已在 Git 2.32(2021 年第二季度)中得到纠正。

请参阅 commit fab78a0commit 462b4e8(2021 年 3 月 18 日),作者是 Matheus Tavares (matheustavares)
(由 Junio C Hamano -- gitster --commit 9210c68 合并,2021 年 3 月 30 日)

<块引用>

checkout:删除条目时不遵循符号链接

签字人:Matheus Tavares

<块引用>

1d718a5(“不要覆盖未跟踪的符号链接”,2011-02-20,Git v1.7.5-rc0 -- merge),symlink.c:check_leading_path() 开始返回FL_ENOENTFL_SYMLINK 的不同代码。
但是它的调用者之一 unlink_entry() 并未针对此更改进行调整,因此它开始遵循要删除条目的前导路径上的符号链接。
修复该问题并添加回归测试。

而且由于我们不再尝试取消此类路径的链接,因此我们也不会收到来自 remove_or_warn() 的警告。

对于常规文件和符号链接情况,最初警告是否有用是值得怀疑的:unlink_entry() 删除了不应再出现在我们正在检查的状态中的跟踪路径。
如果路径的前导目录被另一个文件替换,则表示基名已经不存在,因此无需警告。
当然,我们在路径的目录名后面留下了一个常规文件或符号链接,但是这个文件要么现在没有被跟踪(所以再一次,不需要警告),或者在这个结账的下一阶段它将被一个被跟踪的文件替换< /p>