如果我有一个符号链接的文件或目录并将其提交到 Git 存储库,它会发生什么?
我假设它将它保留为符号链接,直到文件被删除,然后如果您从旧版本中拉回文件,它只会创建一个普通文件。
当我删除它引用的文件时它会做什么?它只是提交悬空链接吗?
如果我有一个符号链接的文件或目录并将其提交到 Git 存储库,它会发生什么?
我假设它将它保留为符号链接,直到文件被删除,然后如果您从旧版本中拉回文件,它只会创建一个普通文件。
当我删除它引用的文件时它会做什么?它只是提交悬空链接吗?
来自linux 符号链接手册(假设您在 Linux 中):
符号链接是一种特殊类型的文件,其内容是一个字符串,该字符串是另一个文件的路径名,即链接所指向的文件。(可以使用 readlink(2) 读取符号链接的内容。)
因此,符号链接是一个文件,就像 aREADME.md
或 a一样Makefile
。Git 只是将链接的内容(即,它链接到的文件系统对象的上述路径)存储在一个“blob”中,就像它存储任何其他文件一样。然后它将名称、模式和类型(包括它是符号链接的事实)存储在表示其包含目录的树对象中。
当您检出包含链接的树时,无论目标文件系统对象是否存在,它都会将该对象恢复为符号链接。
如果您删除符号链接引用的文件,它不会以任何方式影响 Git 控制的符号链接。你会有一个悬空的参考。如果需要,用户可以删除或更改链接以指向有效的内容。
您可以通过将符号链接添加到索引中来查看 Git 对符号链接的作用。索引就像一个预先提交。提交索引后,您可以使用git checkout
将索引中的所有内容带回工作目录。那么,当您向索引添加符号链接时,Git 会做什么呢?
首先,做一个符号链接:
$ ln -s /path/referenced/by/symlink symlink
Git 还不知道这个文件。git ls-files
让您检查索引(-s
类似 printsstat
的输出):
$ git ls-files -s ./symlink
[nothing]
现在,将符号链接添加到索引。当您将文件添加到索引时,Git 会将其内容复制到对象存储中。
$ git add ./symlink
那么,添加了什么?
$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0 symlink
哈希是对在对象存储中创建的打包对象的引用。如果您查看.git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c
存储库的根目录,则可以检查此对象。这是 Git 存储在存储库中的文件,您可以稍后签出。如果你检查这个文件,你会发现它非常小。它不存储链接文件的内容。要确认这一点,请使用以下命令打印打包存储库对象的内容git cat-file
:
$ git cat-file -p 1596f9db1b9610f238b78dd168ae33faa2dec15c
/path/referenced/by/symlink
(注意120000
是ls-files
输出中列出的模式。它类似于100644
常规文件。)
但是当你从存储库中检出这个对象并进入你的文件系统时,Git 会如何处理这个对象呢?这取决于core.symlinks
配置。来自man git-config
:
core.symlinks
如果为 false,则符号链接将作为包含链接文本的小纯文件检出。
因此,使用存储库中的符号链接,在结帐时,您可以得到一个包含完整文件系统路径引用的文本文件,或者一个正确的符号链接,具体取决于core.symlinks
配置的值。
无论哪种方式,符号链接引用的路径的内容都不会存储在存储库中(当然,除非引用的路径也在存储库中)。
“编者注”:这篇文章可能包含过时的信息。请参阅关于自 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 pull
发现一些更新
drwxrwsr-x 2 admin adm 4096 Oct 2 05:54 src/somedir
特殊情况:当 " git checkout
" ( man )删除它正在检出的提交中不存在的路径时,没有足够小心地不遵循符号链接,这已在 Git 2.32 (Q2 2021) 中得到纠正。
请参阅Matheus Tavares ( ) 的提交 fab78a0和提交 462b4e8(2021 年 3 月 18 日)。(由Junio C Hamano 合并 -- --在提交 9210c68中,2021 年 3 月 30 日)matheustavares
gitster
checkout
:删除条目时不要遵循符号链接签字人:Matheus Tavares
在1d718a5(“不要覆盖未跟踪的符号链接”,2011-02-20,Git v1.7.5-rc0 -- merge),
symlink.c
:check_leading_path() 开始返回不同的代码FL_ENOENT
和FL_SYMLINK
。
但是它的调用者之一unlink_entry()
没有针对这种变化进行调整,因此它开始遵循要删除条目的主要路径上的符号链接。
修复它并添加回归测试。而且因为我们不再尝试取消链接这些路径,我们也不会从
remove_or_warn()
.对于常规文件和符号链接的情况,首先该警告是否有用是值得怀疑的:
unlink_entry()
删除在我们检查的状态中不应再存在的跟踪路径。
如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。
当然,我们在路径的目录名中留下了一个常规文件或符号链接,但是这个文件现在要么是未跟踪的(所以再一次,不需要警告),或者它将在此结帐的下一阶段被一个跟踪的文件替换