如果我有一个符号链接的文件或目录,我把它提交到Git仓库,它会发生什么?我会假设它将其作为一个符号链接,直到文件被删除,然后如果您从旧版本中拉回文件,它只会创建一个正常的文件。当我删除它引用的文件时它会做什么?它只提交悬空链接吗?
vsaztqbk1#
从linux symlink manual(假设您使用的是Linux):符号链接是一种特殊类型的文件,其内容是一个字符串,该字符串是另一个文件的路径名,该文件是链接所引用的。(符号链接的内容可以使用readlink(2)读取。)所以符号链接是多一个文件,就像README.md或Makefile一样。Git只存储链接的内容(即它所链接的文件系统对象的上述路径)存储在一个“blob”中,就像它对任何其他文件所做的那样。然后它将名称、模式和类型(包括它是一个符号链接的事实)存储在表示其包含目录的树对象中。当您 checkout 包含链接的树时,无论目标文件系统对象是否存在,它都会将对象恢复为符号链接。如果你删除了符号链接引用的文件,它不会以任何方式影响Git控制的符号链接。你会有一个悬空引用。如果需要,用户可以移除或更改链接以指向有效的内容。
README.md
Makefile
k5ifujac2#
你可以通过将符号链接添加到索引中来了解Git是如何处理符号链接的,索引就像是一个预提交,当索引提交后,你可以使用git checkout将索引中的所有内容带回工作目录。那么,当你向索引添加符号链接时,Git会做些什么呢?首先,创建一个符号链接:
git checkout
$ ln -s /path/referenced/by/symlink symlink
Git还不知道这个文件。git ls-files让你检查你的索引(-s打印类似stat的输出):
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/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c
git cat-file
$ git cat-file -p 1596f9db1b9610f238b78dd168ae33faa2dec15c /path/referenced/by/symlink
(Note 120000是ls-files输出中列出的模式。对于常规文件,它类似于100644。)但是当你把这个对象从仓库 checkout 到文件系统时,Git会怎么处理它呢?这取决于core.symlinks的配置。core.symlinks如果为false,则符号链接将作为包含链接文本的小型纯文本文件 checkout 。因此,使用存储库中的符号链接,在 checkout 时,您可以获得一个引用完整文件系统路径的文本文件,也可以获得一个正确的符号链接,具体取决于core.symlinks config的值。
120000
ls-files
100644
core.symlinks
无论哪种方式,符号链接所引用的路径的内容都不会存储在存储库中(当然,除非所引用的路径也在存储库中)。
c9x0cxw03#
注意当一个目录是一个软链接时会发生什么是很重要的。任何带有更新的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
i7uq4tfw4#
特殊情况:当"git checkout"(man)删除了一个不存在于它正在 checkout 的提交中的路径时,它没有足够小心地不跟随符号链接,这一问题已在Git 2.32(Q2 2021)中得到纠正。参见commit fab78a0、commit 462b4e8(2021年3月18日)和Matheus Tavares ( matheustavares )。(由Junio C Hamano -- gitster --合并至commit 9210c68,2021年3月30日)
matheustavares
gitster
checkout
签署人:马修·塔瓦雷斯在1d718a5("不要覆盖未跟踪的符号链接",2011年2月20日,Git v1.7.5-rc0--merge)中,symlink.c:check_leading_path()开始为FL_ENOENT和FL_SYMLINK返回不同的代码。但是它的调用者之一unlink_entry()没有针对这个变化进行调整,所以它开始跟随要删除条目的前导路径上的符号链接。修复该问题并添加回归测试。而且因为我们不再试图取消这些路径的链接,所以我们也不会收到来自remove_or_warn()的警告。对于常规文件和符号链接的情况,警告是否一开始就有用是值得怀疑的:unlink_entry()将删除在检出到的状态中不应再存在的跟踪路径。如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。当然,我们会在路径的dirname处留下一个常规文件或符号链接,但是这个文件现在要么是未跟踪的(所以同样,不需要警告),要么在 checkout 的下一阶段将被跟踪的文件替换
symlink.c
FL_ENOENT
FL_SYMLINK
unlink_entry()
remove_or_warn()
4条答案
按热度按时间vsaztqbk1#
从linux symlink manual(假设您使用的是Linux):
符号链接是一种特殊类型的文件,其内容是一个字符串,该字符串是另一个文件的路径名,该文件是链接所引用的。(符号链接的内容可以使用readlink(2)读取。)
所以符号链接是多一个文件,就像
README.md
或Makefile
一样。Git只存储链接的内容(即它所链接的文件系统对象的上述路径)存储在一个“blob”中,就像它对任何其他文件所做的那样。然后它将名称、模式和类型(包括它是一个符号链接的事实)存储在表示其包含目录的树对象中。当您 checkout 包含链接的树时,无论目标文件系统对象是否存在,它都会将对象恢复为符号链接。
如果你删除了符号链接引用的文件,它不会以任何方式影响Git控制的符号链接。你会有一个悬空引用。如果需要,用户可以移除或更改链接以指向有效的内容。
k5ifujac2#
你可以通过将符号链接添加到索引中来了解Git是如何处理符号链接的,索引就像是一个预提交,当索引提交后,你可以使用
git checkout
将索引中的所有内容带回工作目录。那么,当你向索引添加符号链接时,Git会做些什么呢?
首先,创建一个符号链接:
Git还不知道这个文件。
git ls-files
让你检查你的索引(-s
打印类似stat
的输出):现在,将符号链接添加到索引中。当你将一个文件添加到索引中时,Git会将其内容复制到对象存储中。
添加了什么?
散列是对对象存储中创建的压缩对象的引用。如果您在存储库根目录下的
.git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c
中查找,可以检查此对象。**这是Git存储在存储库中的文件,您可以稍后 checkout 。**如果您检查此文件,您会发现它非常小。它不存储链接文件的内容。要确认这一点,使用git cat-file
打印打包的存储库对象的内容:(Note
120000
是ls-files
输出中列出的模式。对于常规文件,它类似于100644
。)但是当你把这个对象从仓库 checkout 到文件系统时,Git会怎么处理它呢?这取决于
core.symlinks
的配置。core.symlinks
如果为false,则符号链接将作为包含链接文本的小型纯文本文件 checkout 。
因此,使用存储库中的符号链接,在 checkout 时,您可以获得一个引用完整文件系统路径的文本文件,也可以获得一个正确的符号链接,具体取决于
core.symlinks
config的值。无论哪种方式,符号链接所引用的路径的内容都不会存储在存储库中(当然,除非所引用的路径也在存储库中)。
c9x0cxw03#
注意当一个目录是一个软链接时会发生什么是很重要的。任何带有更新的Git pull都会删除这个链接,并使它成为一个普通的目录。这是我通过艰苦的方式学到的。这里有一些见解和here.
git pull
和一些更新之后 *i7uq4tfw4#
特殊情况:当"
git checkout
"(man)删除了一个不存在于它正在 checkout 的提交中的路径时,它没有足够小心地不跟随符号链接,这一问题已在Git 2.32(Q2 2021)中得到纠正。参见commit fab78a0、commit 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_ENOENT
和FL_SYMLINK
返回不同的代码。但是它的调用者之一
unlink_entry()
没有针对这个变化进行调整,所以它开始跟随要删除条目的前导路径上的符号链接。修复该问题并添加回归测试。
而且因为我们不再试图取消这些路径的链接,所以我们也不会收到来自
remove_or_warn()
的警告。对于常规文件和符号链接的情况,警告是否一开始就有用是值得怀疑的:
unlink_entry()
将删除在检出到的状态中不应再存在的跟踪路径。如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。
当然,我们会在路径的dirname处留下一个常规文件或符号链接,但是这个文件现在要么是未跟踪的(所以同样,不需要警告),要么在 checkout 的下一阶段将被跟踪的文件替换