我最近found about 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
。)
答案 0 :(得分:8)
部分答案位于git glossary,我们find this:
悬空物品
unreachable object即使来自其他无法访问的对象,也不是reachable;悬挂物体没有从object中的任何参考或repository引用它。
(所有链接他们的)。可达性(如果你愿意,可以按照它们的链接)是git提交图中的一个基本概念,我们从一些外部引用开始,如分支或标记名称,以获取图中的起点,然后按照每个节点的出站边找到所有其他节点。
(ref有一个词汇表条目,但不供参考,但引用只有regular dictionary meaning。)
我认为这是最好的解释说明。假设我们有一个如下所示的提交DAG:
C--D--E <-- branch-a
/
A--B--F---G--H <-- branch-b
\ /
I--J--K--L <-- branch-c
节点始终指向左侧,同时也可能指向上方或下方,因此节点E
例如指向D
,其指向C
,指向{ {1}}指向B
。 (A
无处指出:它是 root 节点。)节点A
是合并,并指向G
和F
。此图中的每个节点都是可到达的:我们从所有外部引用(分支)开始并向左走,并发现节点J
到A
在E
上;节点branch-a
,A
和B
到F
位于G
;等等。 (请注意,节点branch-b
和A
位于每个分支上。节点可以在多个分支上的事实是git有点不寻常的事情之一。例如,在mercurial中,每个节点只在一个分支上。以这种特殊的方式,git的分支是流动的,而mercurial是固定的。)
现在让我们看看如果我们删除其中一个分支标签会发生什么。让我们先剥离B
标签。
提交branch-a
不再有任何指向它的内容。它是无法访问,并且在git的术语中 - 悬空。提交E
仅提交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
通过将其ID或内容写入--lost-found
来“复活”(某些)悬挂对象。
(请记住,提交指向以前的提交,而blob只是文本而且从不指向任何内容。当您删除分支时,或者当重新设置并因此放弃的提交链丢失其reflog引用时,您将获得悬空提交,例如,它们非常正常。当你.git/lost-found/
文件的内容时,你会得到悬空blob,然后git add
或git reset
新内容而不先提交,所以摇晃的blob非常正常。git add
不保存悬空树或标记对象。通常不应该有悬空树:树对象只能指向更多的树和blob,并且任何悬空树通常应该被提交指向;并且您必须手动使用git fsck
,然后永远不要引用树,以获得悬挂的树。我不确定为什么标记对象不会复活,因为不小心删除了带注释标记的外部引用将导致悬空的标签对象,能够让它们回来可能会很好。)
git write-tree
检测并恢复悬空或未引用的对象无法访问的对象是那些无法从外部引用访问的对象(主要是分支和标记名称,但git fsck
使用的其他对象如refs/stash
)。悬空对象是无法到达的对象的子集,特别是那些没有入站弧的对象(在图论的理论术语中)。
添加git stash
标志将保存悬空提交的ID - 这使得这些提交,因此任何其他未引用的提交,所有再次引用 - 并解压缩并使所有悬空blob对象可用。