关于版本控制:Git如何处理符号链接?

How does Git handle symbolic links?

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

我假设在文件被删除之前它将作为一个符号链接离开,然后如果从旧版本中拉回来文件,它只会创建一个普通文件。

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


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

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

如果删除symlink引用的文件,它不会以任何方式影响git控制的symlink。你会得到一份悬而未决的推荐信。如果需要,用户可以删除或更改链接以指向有效的内容。


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

通过将文件添加到索引中,可以了解Git对文件的作用。索引就像预提交。提交索引后,可以使用git checkout将索引中的所有内容带回工作目录。那么,当您向索引添加符号链接时,Git会做什么?

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

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

Git还不知道这个文件。git ls-files允许您检查索引(-s打印stat样输出):

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

现在,将符号链接的内容添加到git对象存储区,方法是将其添加到索引中。向索引中添加文件时,Git将其内容存储在Git对象存储中。

1
$ git add ./symlink

那么,添加了什么?

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

哈希是对在Git对象存储区中创建的压缩对象的引用。如果您查看存储库根目录中的.git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c,就可以检查这个对象。这个文件是Git存储的,当您添加和提交一个symlink时,您可以从存储库中签出它。如果您检查这个文件,您会发现它非常小。它不存储链接文件的内容。

(注:120000ls-files输出中列出的模式。对于常规文件来说,它类似于100644

但是,当您将这个对象从存储库签出到文件系统中时,Git会对它做什么呢?这取决于core.symlinks配置。来自man git-config

core.symlinks

If false, symbolic links are checked out as small plain files that contain the link text.

因此,对于存储库中的符号链接,在签出时,根据core.symlinks配置的值,您可以获得一个引用完整文件系统路径的文本文件,或者一个适当的符号链接。

不管怎样,symlink引用的数据都不会存储在存储库中。


"Editor's" note: This post may contain outdated information. Please see comments and this question regarding changes in Git since 1.6.1.

符号链接目录:

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

例子

以前

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

git add/commit/push

1
It remains the same

在发现git pull和一些更新之后

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