我最近发现了大约git fsck
,但链接的答案和git help fsck
给出了各种替代选项的列表,其中一些对未经训练的眼睛来说似乎意味着相同。为了能够很好地使用该工具,我很想了解以下命令之间的区别是什么?
-
git fsck --dangling
-
git fsck --unreachable
-
git fsck --lost-found
此外,它们可以/应该以某些组合一起使用,或者最好不一起使用?
(作为旁注,我特别感兴趣的是git log -G$REGEX $(git fsck --something)
使用它,尽可能广泛地撒网,希望找到我记得在某个时候写过的东西,但我无法用git log -G$REGEX -a
部分答案在 git 词汇表中,我们在其中找到以下内容:
悬空物体
一个无法访问的对象,即使从其他无法访问的对象也无法访问;悬空的对象没有从存储库中的任何引用或对象引用它。
(所有链接他们的(。 可达性(如果你愿意,可以点击他们的链接(是 git 提交图中的一个基本概念,我们从一些外部引用(如分支或标签名称(开始,以获得图中的起点,然后跟随每个节点的出站边缘来查找所有其他节点。
(有一个用于 ref 的词汇表条目,但不用于参考,但参考在这里只有其常规字典含义。
不过,我认为最好用说明性来解释这一点。 假设我们有一个如下所示的提交 DAG:
C--D--E <-- branch-a
/
A--B--F---G--H <-- branch-b
/
I--J--K--L <-- branch-c
节点总是指向左,同时也可能指向向上或向下,因此节点E
,例如,指向D
,它指向C
指向B
指向A
。 (A
无处可寻:它是一个根节点。 节点 G
是一个合并,并指向 F
和 J
。 此图中的每个节点都是可访问的:我们从所有外部引用(分支(开始,向左走,发现A
到E
的节点都在branch-a
;节点A
、B
和F
到G
都在branch-b
;等等。 (请注意,节点A
和B
位于每个分支上。 一个节点可以位于许多分支上这一事实是 git 有点不寻常的事情之一。 例如,在 mercurial 中,每个节点只在一个分支上。 以这种特殊的方式,git 的分支是流动的,而 mercurial 的分支是固定的。
现在让我们看看如果我们擦除其中一个分支标签会发生什么。 让我们先撕下branch-a
标签。
提交E
不再有任何指向它的内容。 它是遥不可及的,而且——用 git 的术语来说——悬而未决。 提交D
只有指向它的提交E
。 由于E
无法访问,因此D
也无法访问,但D
不会悬空,因为E
指向D
。 C
与D
处于相同的状态。 另一方面,节点B
branch-b
可以通过跟随H
到G
到F
到B
,以及跟随H
到G
到J
到I
到B
,以及从branch-c
通过跟随L
到K
到J
到I
到B
。
让我们把branch-a
标签放回去(以便C
到E
再次访问(,然后撕下branch-c
。 这一次L
和K
变得遥不可及。 但是,节点J
仍然是可访问的,方法是从branch-b
开始,从H
到G
再到J
。 在K
和L
提交中,只有L
悬而未决,因为L
指向K
。
使用git fsck
时,正如我在另一个答案中指出的那样,--lost-found
通过将 ID 或内容写入.git/lost-found/
来"复活"(某些(悬挂的对象。
(请记住,提交指向以前的提交,而 blob 只是文本,从不指向任何内容。 例如,当您删除分支时,或者当变基并因此放弃的提交链丢失其 reflog 引用时,您会得到悬而未决的提交,因此它们非常正常。 当您git add
文件的内容时,您会得到悬空的 blob,然后要么git reset
它,要么在不先提交的情况下git add
新内容,因此悬空 blob 是很正常的。 git fsck
不会保存悬空的树或标记对象。 通常不应该有悬空的树:树对象只能指向更多的树和斑点,任何悬空的树通常都应该由提交指向;你必须手动使用git write-tree
,然后永远不要引用树,才能得到一棵悬垂的树。 我不确定为什么标签对象没有复活,因为意外删除注释标签的外部引用会导致标签对象悬空,能够将它们取回可能会很好。
摘要:git fsck
检测和恢复悬空或未引用的对象
无法访问的对象是那些无法从外部引用访问的对象(主要是分支和标签名称,尽管还有其他对象,如git stash
使用的refs/stash
(。 悬空对象是无法到达的对象子集,特别是那些没有入站弧的物体(用图论术语(。
添加 --lost-found
标志将保存悬空提交的 ID(这使得这些提交以及任何其他未引用的提交都再次引用(,并解压缩并使所有悬空 blob 对象可用。