Git如何处理符号链接?

n1bvdmb6  于 2023-02-11  发布在  Git
关注(0)|答案(4)|浏览(139)

如果我有一个符号链接的文件或目录,我把它提交到Git仓库,它会发生什么?
我会假设它将其作为一个符号链接,直到文件被删除,然后如果您从旧版本中拉回文件,它只会创建一个正常的文件。
当我删除它引用的文件时它会做什么?它只提交悬空链接吗?

vsaztqbk

vsaztqbk1#

linux symlink manual(假设您使用的是Linux):
符号链接是一种特殊类型的文件,其内容是一个字符串,该字符串是另一个文件的路径名,该文件是链接所引用的。(符号链接的内容可以使用readlink(2)读取。)
所以符号链接是多一个文件,就像README.mdMakefile一样。Git只存储链接的内容(即它所链接的文件系统对象的上述路径)存储在一个“blob”中,就像它对任何其他文件所做的那样。然后它将名称、模式和类型(包括它是一个符号链接的事实)存储在表示其包含目录的树对象中。
当您 checkout 包含链接的树时,无论目标文件系统对象是否存在,它都会将对象恢复为符号链接。
如果你删除了符号链接引用的文件,它不会以任何方式影响Git控制的符号链接。你会有一个悬空引用。如果需要,用户可以移除或更改链接以指向有效的内容。

k5ifujac

k5ifujac2#

你可以通过将符号链接添加到索引中来了解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 add ./symlink

添加了什么?

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

散列是对对象存储中创建的压缩对象的引用。如果您在存储库根目录下的.git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c中查找,可以检查此对象。**这是Git存储在存储库中的文件,您可以稍后 checkout 。**如果您检查此文件,您会发现它非常小。它不存储链接文件的内容。要确认这一点,使用git cat-file打印打包的存储库对象的内容:

$ git cat-file -p 1596f9db1b9610f238b78dd168ae33faa2dec15c
/path/referenced/by/symlink

(Note 120000ls-files输出中列出的模式。对于常规文件,它类似于100644。)
但是当你把这个对象从仓库 checkout 到文件系统时,Git会怎么处理它呢?这取决于core.symlinks的配置。
core.symlinks
如果为false,则符号链接将作为包含链接文本的小型纯文本文件 checkout 。
因此,使用存储库中的符号链接,在 checkout 时,您可以获得一个引用完整文件系统路径的文本文件,也可以获得一个正确的符号链接,具体取决于core.symlinks config的值。

无论哪种方式,符号链接所引用的路径的内容都不会存储在存储库中(当然,除非所引用的路径也在存储库中)。

c9x0cxw0

c9x0cxw03#

  • "编者注":此帖子可能包含过时的信息。请查看评论和this question了解Git自1.6.1以来的更改。*
    • 符号链接目录:**

注意当一个目录是一个软链接时会发生什么是很重要的。任何带有更新的Git pull都会删除这个链接,并使它成为一个普通的目录。这是我通过艰苦的方式学到的。这里有一些见解和here.

    • 示例**
  • 之前 *
ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir
  • 一月一日 *
It remains the same
  • git pull和一些更新之后 *
drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir
i7uq4tfw

i7uq4tfw4#

特殊情况:当"git checkout"(man)删除了一个不存在于它正在 checkout 的提交中的路径时,它没有足够小心地不跟随符号链接,这一问题已在Git 2.32(Q2 2021)中得到纠正。
参见commit fab78a0commit 462b4e8(2021年3月18日)和Matheus Tavares ( matheustavares )
(由Junio C Hamano -- gitster --合并至commit 9210c68,2021年3月30日)

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

签署人:马修·塔瓦雷斯
1d718a5("不要覆盖未跟踪的符号链接",2011年2月20日,Git v1.7.5-rc0--merge)中,symlink.c:check_leading_path()开始为FL_ENOENTFL_SYMLINK返回不同的代码。
但是它的调用者之一unlink_entry()没有针对这个变化进行调整,所以它开始跟随要删除条目的前导路径上的符号链接。
修复该问题并添加回归测试。
而且因为我们不再试图取消这些路径的链接,所以我们也不会收到来自remove_or_warn()的警告。
对于常规文件和符号链接的情况,警告是否一开始就有用是值得怀疑的:unlink_entry()将删除在检出到的状态中不应再存在的跟踪路径。
如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。
当然,我们会在路径的dirname处留下一个常规文件或符号链接,但是这个文件现在要么是未跟踪的(所以同样,不需要警告),要么在 checkout 的下一阶段将被跟踪的文件替换

相关问题