173

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

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

$ git fetch origin

$ git fsck --unreachable
$ git fsck

没有输出,没有任何悬空(对吗?)。但是提交存在

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

并且无法通过任何分支访问,因为

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

没有输出。

该提交的具体状态是什么?如何列出处于相似状态的所有提交?我怎样才能删除这样的提交?

4

8 回答 8

301

要删除所有悬空提交(包括那些仍然可以从 stash 和其他 reflog 访问的提交),请执行以下操作:

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

但请确定这是您想要的。我建议您阅读手册页,但要点如下:

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

存储是使用 reflog 实现的(即不是分支或标签)。这意味着它们会受到垃圾收集。

git gc做一些其他的事情,但它们在这里不相关,也不危险。

两周内无法访问的对象不会被删除,因此我们使用--prune=now它的意思是“删除之前创建的无法访问的对象”。

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

因此,我们还必须删除 reflogs 才能真正删除从分支中无法访问的所有内容。我们通过过期--allreflogs 来做到这一点。git 再次保留一些 reflogs 来保护用户,所以我们必须再次告诉它不要这样做:--expire-unreachable=now.

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

于 2010-12-24T22:42:02.670 回答
81

没有输出,没有任何悬空(对吗?)

请注意,从您的 reflog 中引用的提交被认为是可访问的。

该提交的具体状态是什么?如何列出具有相似状态的所有提交

通过--no-reflogs说服git fsck将它们展示给您。

我怎样才能删除这样的提交?

一旦您的 reflog 条目过期,这些对象也将由git gc.

到期由gc.pruneexpiregc.reflogexpiregc.reflogexpireunreachable设置控制。参照。git help config.

默认值都非常合理。

于 2010-09-22T00:57:32.493 回答
29

在遵循此线程中的所有建议之后,我仍然遇到了同样的问题:

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>并重新进行了清理,旧的提交消失了。

于 2017-03-09T14:28:25.313 回答
14
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

可能只是需要

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

还可以从远程报告分支

于 2011-03-13T01:36:42.310 回答
8

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

但即使在跑步之后

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

我的提交仍然可以使用git show <commit>. 这是因为它的分离/悬空“分支”中的一个提交被标记了。我删除了标签,再次运行上述命令,我很成功。git show <commit>返回fatal: bad object <commit>- 正是我需要的。希望这可以帮助像我一样陷入困境的其他人。

于 2016-05-19T23:28:45.960 回答
8

我不小心遇到了同样的情况,发现我的存储包含对无法访问的提交的引用,因此假定的无法访问的提交可以从存储中访问。

这些是我所做的,以使其真正无法访问。

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now
于 2017-09-22T03:49:17.993 回答
2

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

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

于 2010-09-21T23:45:58.387 回答
0

如果存储确实是“不存在”而不是标签的存储,
git fsck --full
则可能会有所帮助。当没有其他解决方案时,它对我有用。

Git:Remove broken stash比这个线程更准确地描述了我的问题)

于 2021-08-14T22:04:01.537 回答