列出并删除没有分支的Git提交(悬空?)

时间:2010-09-21 23:29:31

标签: git branch git-dangling

我有一个Git存储库,其中包含大量没有特定分支的提交,我可以git show,但是当我尝试列出包含它们的分支时,它不会报告任何内容。

我认为这是悬挂的提交/树问题(由于-D分支),所以我修剪了回购,但之后我仍然看到相同的行为:

$ git fetch origin

$ git fsck --unreachable
$ git fsck

没有输出,没有悬空(对吧?)。但提交存在

$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...

并且无法通过任何分支到达

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

没有输出。

该提交的状态究竟是什么?如何列出处于类似状态的所有提交?如何删除那些提交?

7 个答案:

答案 0 :(得分:232)

要删除所有悬空提交以及可从reflog中访问的提交,请执行以下操作:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

但请确保这是你想要的。我建议你阅读手册页,但这里是要点:

git gc删除无法访问的对象(提交,树,blob(文件))。如果某个对象不属于某个分支的历史记录,则该对象无法访问。实际上它有点复杂:

git gc做了其他一些事情,但它们在这里没有关系,也没有危险。

未删除不到两周的无法访问的对象,因此我们使用--prune=now,这意味着“删除之前创建的无法访问的对象”。

也可以通过reflog访问对象。虽然分支记录了某个项目的历史记录,但是reflog记录了这些分支的历史记录。如果你修改,重置等提交将从分支历史记录中删除,但是如果你意识到你犯了错误,git会保留它们。 Reflogs是一种方便的方法,可以找出在分支(或HEAD)上执行的破坏性(和其他)操作,从而更容易撤消破坏性操作。

因此,我们还必须删除reflog以实际删除从分支无法访问的所有内容。我们通过--all reflogs到期来实现这一目标。 git再次保留了一些reflog以保护用户,所以我们再次告诉它不要这样做:--expire-unreachable=now

由于我主要使用reflog来从破坏性操作中恢复,所以我通常使用--expire=now来完全消除reflog。

答案 1 :(得分:70)

  

没有输出,没有悬空(对吧?)

请注意,您的reflog引用的提交被视为可访问。

  

该提交的状态究竟是什么?如何列出具有类似状态的所有提交

通过--no-reflogs说服git fsck向您展示。

  

如何删除那些提交?

一旦您的reflog条目过期,这些对象也将被git gc清除。

到期时间由gc.pruneexpiregc.reflogexpiregc.reflogexpireunreachable设置规定。参看git help config

默认值都很合理。

答案 2 :(得分:14)

我有同样的问题,仍然遵循这个帖子中的所有建议:

git reflog expire --expire-unreachable=now --all
git gc --prune=now
git fsck --unreachable --no-reflogs   # no output
git branch -a --contains <commit>     # no output
git show <commit>                     # still shows up

如果它不是reflog而不是分支,...它必须是标签

git tag                             # showed several old tags created before the cleanup

我使用git tag -d <tagname>删除了标记并重新进行了清理,旧的提交已经消失。

答案 3 :(得分:13)

git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

可能只需要

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

还报告来自遥控器的分支

答案 4 :(得分:5)

我有类似的问题。我跑了git branch --contains <commit>,它没有像问题那样返回任何输出。

但即使在跑完

之后
git reflog expire --expire-unreachable=now --all
git gc --prune=now

我仍然可以使用git show <commit>访问我的提交。这是因为其分离/悬挂&#34;分支中的一个提交&#34;被标记的。我删除了标签,再次运行上面的命令,我是金色的。 git show <commit>返回fatal: bad object <commit> - 正是我所需要的。希望这可以帮助那些和我一样困难的人。

答案 5 :(得分:2)

git gc --prune=<date>默认修剪两周前的对象。您可以设置更近的日期。但是,创建松散对象的git命令通常会运行git gc --auto(如果它们的数量超过配置变量gc.auto的值,则修剪松散的对象)。

您确定要删除这些提交吗? gc.auto的默认设置将确保松散的对象不占用不合理的内存量,并且将松散的对象存储一段时间通常是个好主意。这样,如果您明天意识到已删除的分支包含您需要的提交,则可以恢复它。

答案 6 :(得分:2)

我意外地遇到了同样的情况,发现我的藏匿条件包含对无法访问的提交的引用,因此可以从存储中找到假定的无法访问的提交。

这些是我为使它真正无法到达所做的。

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now