什么是Git存储库中的悬挂提交和Blob,它们来自哪里?

236

我正在寻找关于悬空提交和Blob的基本信息。

我的代码库似乎没问题。但是我第一次运行 git fsck 命令,看看它做了什么,然后我得到了一个很长的“悬空Blob”列表和单个的“悬空提交”。

这些东西是什么?它们从哪里来?它们是否表明我的代码库状态有任何异常(好或坏)?

5个回答

145

在使用 Git 仓库时,您可能会回退操作,进行其他移动,这会导致中间 blob 甚至是一些 Git 帮助您避免信息丢失的操作。

最终(有条件地,根据git gc 手册页面)将执行垃圾回收并清除这些内容。您也可以通过调用垃圾收集过程 git gc 来强制执行它。

有关此内容的更多信息,请参见 git-scm 站点上的Maintenance and Data Recovery

手动运行 GC 默认会将该命令运行时间之前的两周留作安全网。实际上,偶尔运行 GC 有助于确保高效使用 Git 仓库。但是,在销毁可能对您重要的内容之前,您应该了解它正在做什么。


18
可以说,除非我认为我的代码库出了问题,否则使用 git gc 安全地删除这些东西;同时,因为这些悬空的部分是正常的,而且 Git 已经处理了它们,所以我无需担心。 - doub1ejack
9
那将是一个公正的评估。 - vgoff
13
每当你使用“git add”命令添加文件但未提交该文件的确切版本时,就会产生一个悬空blob。不必担心,这是正常现象。 - canton7
15
通常情况下,你不应该手动运行垃圾回收。这是一个不好的习惯,因为Git会在需要时自动进行垃圾回收。手动运行的缺点是你失去了恢复悬空的blob和提交的能力,虽然现在可能不需要,但将来可能需要。一旦运行垃圾回收,就会削弱Git的一些非常有用的还原功能。请谨慎使用,只有在特殊情况下才使用。——让Git自己做它应该做的事情即可。 - Elijah Lynn
很抱歉,我有两个悬空的 blob,它们非常顽固,我不知道它们是什么,即使使用 'git gc' 或者 'git gc --aggressive' 命令也无法删除。显然,答案可能涵盖了一些创建悬空 blob 的情况。 - Motti Shneor
1
@MottiShneor 我原本希望“甚至包括Git为避免信息丢失所做的一些事情”可以涵盖博客创建的其余部分。但你可能是对的,这仍然只涵盖了某些创建这些悬空blob的方法。 - vgoff

140

悬挂Blob = 一种在暂存区/索引中被更改了,但从未提交的内容。Git的一个惊人之处在于,一旦它被添加到暂存区,您总是可以将其恢复,因为这些Blob就像提交一样具有哈希值!

悬挂提交 = 没有任何子提交、分支、标签或其他引用直接链接的提交。您也可以将它们恢复回来!


5
“ancestors”应该改为“后代”?一般来说,你无法通过它的祖先访问任何git提交。 - Phil Miller
1
我仍然在你的回答中看到“ascendants”。似乎你7月2日的版本没有更正这个错别字。 - iclman
1
@ElijahLynn 没错。我想我有点匆忙地阅读了这些讨论。悬挂提交没有任何后代/子级,并且没有被标签或分支引用。 - iclman
1
严格来说,如果我有一个分离的HEAD,然后创建一个提交,那么这个新提交已经被认为是“悬空”的了吗?还是只有当我将HEAD移动到另一个提交/分支时才算? - msa
“Stash” 是如何被认为的?是一个提交吗?还是一个 blob? - Motti Shneor
显示剩余8条评论

78

12
实际上,大多数用户不应该需要这样做,如果他们确实需要这样做,那么可能是出于编程的需求。在我看来,为了删除悬空提交所节省的磁盘空间或提高速度并不值得花费这种精力。 - Elijah Lynn
5
这个回答涉及到另一个问题。 - Elijah Lynn
链接已经失效(超时)。 - Peter Mortensen

26
一个悬挂提交指的是没有关联引用的提交,即无法访问它。
例如,考虑下面的图表。假设我们删除了分支featureX而没有合并它的更改,则提交D将成为一个悬挂提交,因为没有与之关联的引用。如果它已经合并到主干上,则HEAD和master的引用会指向提交D,并且即使我们删除了featureX,它也不再是悬挂提交。阅读图表后的注释以更好地了解这一点。
Git会自动垃圾回收即处理悬挂提交。我们可以使用git reflog来恢复被删除但未合并的分支(悬挂提交)。只有在本地对象存储中存在时,才能恢复已删除的提交。如果已进行垃圾回收,则我们无法恢复它。

enter image description here

请注意,分支名称即分支标签实际上是对分支上最新提交或分支尖端的引用。在上面的图表中,featureX、master和HEAD只是对特定提交的引用。featureX和master标签分别指向它们各自分支上的最新提交。HEAD通常指当前检出分支的尖端(在本例中为master)。如果您检出当前分支上的早期提交,则HEAD将处于分离状态,即它会指向早期提交而不是最新提交。还要注意,HEAD被称为符号引用,因为它实际上指向当前分支标签,任何分支标签都始终指向分支的尖端。因此,在正常情况下,HEAD间接指向最新提交。
顺便提一句,注意Git将其提交图/历史表示为有向无环图。每个提交都有对其父提交的引用。因此,提交图表中的箭头从子提交指向父提交。我们需要一个对最新子提交的引用才能到达分支上的旧提交。
PS - 上述图表和理解来源于这个免费课程。尽管该课程相当古老,但知识仍然相关。

8
如果您“修正”了提交,也会出现悬挂提交。例如,您完成了许多工作,测试了它,并提交了所有文件,然后记住您忘记更新 README 文件。因此,您快速更改并添加该文件,然后使用“git commit --amend”。这将创建一个新的提交,链接到提交历史记录中,原始提交留下来悬挂着。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接