Git如何处理符号链接?

Ale*_*lex 1515 git version-control symlink

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

我会假设它将它作为符号链接留下,直到文件被删除,然后如果你从旧版本拉回文件它只是创建一个普通文件.

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

CB *_*ley 1269

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

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

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

  • BTW.如果您使用的FAT文件系统不支持符号链接,并且您的存储库使用它们,您可以将`core.symlinks`配置变量设置为false,并且符号链接将被检出为包含链接文本的小型纯文本文件. (313认同)
  • 我毫不犹豫地对高度赞成的答案发表评论,但我认为这句话"就像普通档案一样"可能会误导新人. (23认同)
  • @JakubNarębski我之前看过这个.我们的仓库中有一个文本文件,其中包含一行,即我们使用的库的路径.无法弄清楚它的目的是什么.我现在知道发生了什么. (14认同)
  • (用完了编辑时间)它就像一个普通的文件,因为内容是一个blob.关键区别在于,对于普通文件,blob是文件内容,但对于符号链接,blob具有链接到的文件的路径名.@JakubNarębski关于"小纯文本文件"..你希望它们很小而且文本很好但当然blob是一个blob,可能是巨大的二进制文件.当文件被错误地输入为符号链接时,请参阅http://stackoverflow.com/questions/18411200/git-unable-to-create-symlink-file-name-too-long. (10认同)
  • 请务必检查符号链接的全局设置和符号链接的本地设置。如果设置是从 TortiseGit 或 windows 复制过来的,那么你可能会用 `symlinks = false` 来弄乱它们。 (4认同)
  • @MatthewHannigan - 我犹豫是否要评论高度赞扬的评论;)但符号链接文件的实际文件内容字面上是“它链接到的文件的路径名”。Blob 内容没有区别。(对于其他操作系统/FS 可能有所不同,但对于至少大多数(全部?)Unix-y 环境,如 mac、linux、bsd 等来说都是如此。) (2认同)

Dmi*_*sky 228

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


您可以通过查看将文件添加到索引时的功能来了解Git对文件执行的操作.索引就像预先提交一样.提交索引后,您可以使用git checkout将索引中的所有内容返回到工作目录中.那么,当您向索引添加符号链接时,Git会做什么?

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

$ ln -s /path/referenced/by/symlink symlink
Run Code Online (Sandbox Code Playgroud)

Git还不知道这个文件.git ls-files让你检查你的索引(-s打印stat类似输出):

$ git ls-files -s ./symlink
[nothing]
Run Code Online (Sandbox Code Playgroud)

现在,通过将符号链接的内容添加到索引,将其添加到Git对象库中.将文件添加到索引时,Git将其内容存储在Git对象库中.

$ git add ./symlink
Run Code Online (Sandbox Code Playgroud)

那么,添加了什么?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink
Run Code Online (Sandbox Code Playgroud)

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

(注意输出中120000列出的模式ls-files.它类似于100644常规文件.)

但是当你从存储库和文件系统中检查出来时,Git会对这个对象做些什么呢?这取决于core.symlinks配置.来自man git-config:

core.symlinks

如果为false,则将符号链接签出为包含链接文本的小型纯文本.

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

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

  • 比起公认的答案,我更喜欢这个答案。 (4认同)

She*_*har 147

"编辑"注:此帖可能包含过时的信息.请参阅自1.6.1以来关于Git变化的评论和这个问题.

符号链接目录:

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

之前

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir
Run Code Online (Sandbox Code Playgroud)

git add/commit/push

It remains the same
Run Code Online (Sandbox Code Playgroud)

之后git pull发现了一些更新

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir
Run Code Online (Sandbox Code Playgroud)

  • 现在似乎已修复此行为,请参阅:http://stackoverflow.com/a/1943656/1334781 (23认同)
  • 这种行为是出现在所有版本的git上还是已经修复了? (21认同)
  • 值得注意的是,这些关于符号链接目录的警告**不适用于版本化的符号链接.有问题的主要问题是人们将部分或全部工作树符号化为不同的路径(例如,在具有更多磁盘空间的不同分区上),并期望git通过现有的符号链接检出代码.也就是说,如果您的项目包含文件或目录的版本化符号链接,则正常的符号链接作为blob行为将保留符号链接,正确地对这些符号链接进行版本更改,否则将按预期工作. (4认同)
  • @RonWertlen 这是同一问题的链接。 (3认同)
  • Shekar:你会编辑你的答案来反映近年来git的变化吗? (2认同)

Von*_*onC 5

特殊情况:当“ git checkoutman删除它正在签出的提交中不存在的路径时,它不够小心,没有遵循符号链接,这一问题已在 Git 2.32(2021 年第 2 季度)中得到纠正。

请参阅Matheus Tavares的提交 fab78a0提交 462b4e8(2021 年 3 月 18 日) ( )(由Junio C Hamano 合并 -- --提交 9210c68中,2021 年 3 月 30 日)matheustavares
gitster

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

签署人:马修斯·塔瓦雷斯

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()删除不应再出现在我们正在检查的状态中的跟踪路径。
如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。
当然,我们在路径的目录名中留下了一个常规文件或符号链接,但该文件现在要么未被跟踪(所以再次,无需警告),要么在结帐的下一阶段它将被跟踪文件替换