ChatGPT解决这个技术问题 Extra ChatGPT

Git 如何处理符号链接?

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

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

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

.gitignore 将符号链接视为文件而非文件夹。
好吧,显然这个问题比答案所暗示的要多。例如,我想知道以下问题:如果我在存储库中创建指向该存储库中某个大文件的符号链接,推送更改,然后将这些更改拉到另一台机器,会发生什么?大文件会在两个位置都作为大文件存储,还是会保留符号链接,以便在新机器上,链接文件指向原始大文件?
这是一个旧线程,但此评论可能仍然有用。针对 jviesem,软链接基本上是一个文件名与另一个文件同名的文件。因此,一旦您将其拉到另一台机器上,该链接将被下载,并且它将具有原始文件系统上的大文件的名称。如果在新机器上该名称无效,则链接将具有无效名称。大文件不会下载到新机器上。
@lasaro,避免git repo中链接断开的方法是在制作符号链接时始终使用相对路径,根据需要使用 ../..
请注意,在大多数 Windows 版本中,您需要提升权限才能创建符号链接。如果您在 Windows 上并且 git pull 创建一个文件而不是符号链接,请尝试以管理员身份运行您的 Git 客户端。

o
onlycparra

linux symlink manual(假设您在 Linux 中):

符号链接是一种特殊类型的文件,其内容是一个字符串,该字符串是另一个文件的路径名,即链接所指向的文件。 (可以使用 readlink(2) 读取符号链接的内容。)

因此,符号链接是一个文件,就像 README.mdMakefile。 Git 只是将链接的内容(即,它链接到的文件系统对象的上述路径)存储在一个“blob”中,就像它存储任何其他文件一样。然后它将名称、模式和类型(包括它是符号链接的事实)存储在表示其包含目录的树对象中。

当您检出包含链接的树时,无论目标文件系统对象是否存在,它都会将该对象恢复为符号链接。

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


顺便提一句。如果您在不支持符号链接的文件系统(如 FAT)上,并且您的存储库使用它们,则可以将 core.symlinks 配置变量设置为 false,并且符号链接将作为包含链接文本的小型纯文本文件检出。
@JakubNarębski 我以前看过这个。我们的仓库中有一个文本文件,其中一行是我们使用的库的路径。无法弄清楚它的目的是什么。我现在知道发生了什么。
我不愿评论高度赞成的答案,但我认为“就像普通文件一样”的措辞可能会误导新手。它就像一个普通文件,只是内容在一个 blob 中。关键区别在于,对于普通文件,blob 是文件内容,但对于符号链接,blob 具有它链接到的文件的路径名。
@JakubNarębski 关于“小型纯文本文件”..您希望它们很小并且是文本,但当然 blob 是一个 blob,并且可能是巨大的二进制文件。有关文件被错误键入为符号链接的情况,请参见 stackoverflow.com/questions/18411200/…
请务必检查符号链接的全局设置和符号链接的本地设置。如果设置是从 TortiseGit 或 windows 复制过来的,那么您可能会让 symlinks = false 弄乱它们。
D
Dmitry Minkovsky

您可以通过将符号链接添加到索引中来查看 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 存储在存储库中的文件,您可以稍后签出。如果您检查此文件,您会发现它非常小。它不存储链接文件的内容。要确认这一点,请使用 git cat-file 打印打包存储库对象的内容:

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

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

但是当你从存储库中检出这个对象并进入你的文件系统时,Git 会如何处理这个对象呢?这取决于 core.symlinks 配置。从 man git-config

core.symlinks 如果为 false,则符号链接将作为包含链接文本的小纯文件检出。

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

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


如果存储在远程中的链接路径指向存储库内的路径,它是否保证是相对的?到回购之外的路径呢?它是绝对的还是相对于项目的根目录?这取决于链接的制作方式吗?
是的,我认为这取决于您如何创建符号链接。如果您创建它并且目标以 / 为前缀,那么它将是绝对的,并且可能指向您的存储库之外。否则,它将是相对的。如果它是相对的并且指向您的存储库,那么它应该是可移植的,至少在类 Unix 系统之间是可移植的。
@geekley 不确定我是如何在编辑过程中意外删除的,但是您可以使用 git cat-file -p 查看 git 存储对象的内容,因此如果您的符号链接的哈希是 c6e5580589892eb40407c74a825afaa6c9315787,您可以执行 git cat-file -p c6e5580589892eb40407c74a825afaa6c9315787 并查看该包文件的内容,这只是一个符号链接
P
Peter Mortensen

“编者注”:这篇文章可能包含过时的信息。请参阅关于自 1.6.1 以来 Git 更改的评论和此问题。

符号链接目录:

重要的是要注意当目录是软链接时会发生什么。任何带有更新的 Git 拉取都会删除链接并使其成为普通目录。这是我努力学习的方法。一些见解 herehere.

例子

 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 通过现有的符号链接检查代码。也就是说,如果您的项目包含指向文件或目录的版本化符号链接,则正常的 symlink-as-blob 行为将保留符号链接,正确地对这些符号链接进行版本更改,否则按预期工作。
这种行为是否存在于所有版本的 git 上,或者是否已修复?
现在看来此行为已修复,请参阅:stackoverflow.com/a/1943656/1334781
Shekar:你会编辑你的答案以反映近年来 git 的变化吗?
@RonWertlen 这是同一个问题的链接。
V
VonC

特殊情况:当 "git checkout"(man) 删除它正在检出的提交中不存在的路径时,没有注意不遵循符号链接,这有已使用 Git 2.32(2021 年第二季度)更正。

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

结帐:删除条目时不要遵循符号链接签名者:Matheus Tavares

在 1d718a5(“不要覆盖未跟踪的符号链接”,2011-02-20,Git v1.7.5-rc0 -- 合并),symlink.c:check_leading_path() 开始为 FL_ENOENT 和 FL_SYMLINK 返回不同的代码。但是它的调用者之一 unlink_entry() 并没有针对这种变化进行调整,因此它开始遵循要删除条目的前导路径上的符号链接。修复它并添加回归测试。而且因为我们不再尝试取消链接这些路径,所以我们也不会收到来自 remove_or_warn() 的警告。对于常规文件和符号链接的情况,首先该警告是否有用是值得怀疑的:unlink_entry() 删除了在我们正在检查的状态中不应再存在的跟踪路径。如果路径的前导目录被另一个文件替换,则意味着基本名称已经不存在,因此不需要警告。当然,我们在路径的目录名中留下了一个常规文件或符号链接,但是这个文件现在要么是未跟踪的(所以再一次,不需要警告),或者它将在此结帐的下一阶段被一个跟踪的文件替换