列出和删除不在分支下的 Git 提交(悬空?)

发布于 2024-09-24 06:16:24 字数 570 浏览 4 评论 0原文

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

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

$ git fetch origin

$ git fsck --unreachable
$ git fsck

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

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

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

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

没有输出。

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

I've got a Git repository with plenty of commits that are under no particular branch, I can git show them, but when I try to list branches that contain them, it reports back nothing.

I thought this is the dangling commits/tree issue (as a result of -D branch), so I pruned the repo, but I still see the same behavior after that:

$ git fetch origin

$ git fsck --unreachable
$ git fsck

No output, nothing dangling (right?). But the commit exists

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

and it is not reachable through any branch as

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

gives no output.

What exactly is the state of that commit? How can I list all commits in a similar state? How can I delete commits like those?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

最佳男配角 2024-10-01 06:16:24

要删除所有悬空提交(包括仍然可以从存储和其他引用日志访问的提交),请执行以下操作:

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

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

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

存储是使用引用日志实现的(即不是分支或标签)。这意味着它们会受到垃圾收集的影响。或者,更明确地说:运行上述命令将删除所有存储

git gc 还做了一些其他的事情,但它们与这里无关,也不危险。

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

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

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

由于我主要使用引用日志从破坏性操作中恢复,因此我通常使用 --expire=now 来代替,这会完全清除引用日志。

To remove all dangling commits (including those still reachable from stashes and other reflogs) do this:

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

But be certain that this is what you want. I recommend you read the man pages but here is the gist:

git gc removes unreachable objects (commits, trees, blobs (files)). An object is unreachable if it isn't part of the history of some branch. Actually it is a bit more complicated:

Stashes are implemented using the reflog (i.e not not branches or tags). That means that they are subject to garbage collection. Or, to make it more explicit: running the above commands will delete all your stashes.

git gc does some other things but they are not relevant here and not dangerous.

Unreachable objects that are younger than two weeks are not removed so we use --prune=now which means "remove unreachable objects that were created before now".

Objects can also be reached through the reflog. While branches record the history of some project, reflogs record the history of these branches. If you amend, reset etc. commits are removed from the branch history but git keeps them around in case you realize that you made a mistake. Reflogs are a convenient way to find out what destructive (and other) operations were performed on a branch (or HEAD), making it easier to undo a destructive operation.

So we also have to remove the reflogs to actually remove everything not reachable from a branch. We do so by expiring --all reflogs. Again git keeps a bit of the reflogs to protect users so we again have to tell it not to do so: --expire-unreachable=now.

Since I mainly use the reflog to recover from destructive operations I usually use --expire=now instead, which zaps the reflogs completely.

水染的天色ゝ 2024-10-01 06:16:24

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

请注意,引用日志中引用的提交被认为是可达的。

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

--no-reflogs 说服 git fsck 向您显示它们。

如何删除此类提交?

一旦您的引用日志条目过期,这些对象也将被 git gc 清理。

过期由 gc.pruneexpiregc.reflogexpiregc.reflogexpireunreachable 设置控制。比照。 git 帮助配置

默认值都是相当合理的。

No output, nothing dangling (right?)

Note that commits referred to from your reflog are considered reachable.

What exactly is the state of that commit? How can I list all commits with similar state

Pass --no-reflogs to convince git fsck to show them to you.

How can I delete commits like those?

Once your reflog entries are expired, those objects will then also be cleaned up by git gc.

Expiry is regulated by the gc.pruneexpire, gc.reflogexpire, and gc.reflogexpireunreachable settings. Cf. git help config.

The defaults are all quite reasonable.

别忘他 2024-10-01 06:16:24

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

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

如果它不是引用日志也不是分支,...它必须是标签

git tag                             # showed several old tags created before the cleanup

我使用 git tag -d删除了标签并重新进行了清理,旧的提交消失了。

更新:如果事实证明它不是标签,它也可能是一个藏匿处! 检查此答案此答案

I had the same issue, still after following all the advice in this thread:

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

If it's not a reflog and not a branch, ...it must be a tag!

git tag                             # showed several old tags created before the cleanup

I removed the tags with git tag -d <tagname> and redid the cleanup, and the old commits were gone.

Update: If it turns out it's not a tag, it might also be a stash! Check this answer and this answer

听闻余生 2024-10-01 06:16:24
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

可能只需要

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

报告远程分支

git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

probably just needs to be

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

to also report on branches from remotes

2024-10-01 06:16:24

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

我所做的就是让它真正变得遥不可及。

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

I accidentally hit the same situation and found my stashes contain reference to the unreachable commit, and thus the presumed unreachable commit was reachable from stashes.

These were what I did to make it truly unreachable.

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now
花间憩 2024-10-01 06:16:24

我有类似的问题。我运行了 git Branch --contains,它没有返回任何输出,就像问题中一样。

但即使在运行之后,

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

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

I had a similar issue. I ran git branch --contains <commit>, and it returned no output just like in the question.

But even after running

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

my commit was still accessible using git show <commit>. This was because one of the commits in its detached/dangled "branch" was tagged. I removed the tag, ran the above commands again, and I was golden. git show <commit> returned fatal: bad object <commit> - exactly what I needed. Hopefully this helps someone else that was as stuck as I was.

白云悠悠 2024-10-01 06:16:24

TL:博士;

提交可以通过以下方式引用:

  • 分支
  • 标签 (!)
  • 存储 (!!)
  • “替换”(!!?)

使用此命令查找它的内容正是:

git for-each-ref --contains <SHA>

长版本

我对存储库做了一个 filter-repo 来清理一些大文件。

显然最终导致了一些悬而未决的提交。我尝试了所有答案,但没有任何效果。

git branch --contains <SHA>           # nothing!
git fsck --unreachable --no-reflogs   # nothing!

然后,由于 这个答案,我找到并删除了一个标签,

但提交仍然显示出来!

所以我最终运行了这个命令:

git for-each-ref --contains <SHA>

它返回了

1b9bf9c63209a4728b2d3dc7946da836dc331bbd commit refs/stash

Bingo!

我运行了 git stash - 它(奇怪地)是空的。如果我的存储中没有任何内容,存储如何引用提交?

然而,运行git stash drop几次已经删除了一些基于过时分支的被上帝遗弃的“悬挂”存储,终于我能够gc提交,我的仓库立即变小了 15MB。

更长的版本

(来自另一个用户)我使用了上面的提示,但它返回了

4c79e05b102c673e1f60242c022ff06e017b9a1d commit refs/replace/2acd8f182e14d7d367b3469fd8751f2d9738a884

到底是什么替换?

git replace -h

显示您可以列出删除和编辑这些“替换对象”。诡异的。运行 git Replace -d 2acd8f 会删除提交!

TL:DR;

A commit can be referenced by:

  • a branch
  • a tag (!)
  • a stash (!!)
  • a "replace" (!!?)

Use this command to find what it is exactly:

git for-each-ref --contains <SHA>

Long version

I did a filter-repo of the repo to clean up some huge files.

Obviously ended up with some dangling commits. I tried all the answers, and nothing was working.

git branch --contains <SHA>           # nothing!
git fsck --unreachable --no-reflogs   # nothing!

Then I found and deleted a tag thanks to this answer

Still the commit kept shwoing up!

So I finally ran this command:

git for-each-ref --contains <SHA>

And it returned

1b9bf9c63209a4728b2d3dc7946da836dc331bbd commit refs/stash

Bingo!

I ran git stash - and it was (oddly) empty. How can a stash reference a commit if I have nothing in my stash?

However running git stash drop several times has deleted some god forsaken "dangling" stashes based on obsolete branches and finally I was able to gc that commit, and my repo instantly got 15MB smaller.

Longer version

(From another user) I used the tips above but it returned

4c79e05b102c673e1f60242c022ff06e017b9a1d commit refs/replace/2acd8f182e14d7d367b3469fd8751f2d9738a884

what the heck is replace?

git replace -h

shows you can list delete and edit these 'replacement objects'. Weird. Running git replace -d 2acd8f removes the commit!

[浮城] 2024-10-01 06:16:24

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

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

git gc --prune=<date> defaults to prune objects older than two weeks ago. You could set a more recent date. But, git commands that create loose objects generally will run git gc --auto (which prunes loose objects if their number exceeds the value of configuration variable gc.auto).

Are you sure that you want to delete these commits? gc.auto's default setting will ensure that the loose objects do not take up an unreasonable amount of memory, and storing loose objects for some amount of time is generally a good idea. That way, if you realize tomorrow that your deleted branch contained a commit you needed, you can recover it.

最单纯的乌龟 2024-10-01 06:16:24

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

Git:删除损坏的存储比这个线程更准确地描述了我的问题)

If the stash is truly a stash that "doesn't exist" and not a tag,
git fsck --full
may help. It worked for me when no other solution did.

(Git: Remove broken stash describes my problem more accurately than this thread)

朕就是辣么酷 2024-10-01 06:16:24

我知道这不是一个好的解决方案,但我做了一个 filter-branch 并最终得到了重复的、无法访问的提交,这些提交不属于任何分支,但无法自动删除它们,我尝试了每一个解决方案发布在这里,绝对没有任何效果。因此,我推送到远程存储库(github),删除了本地存储库,然后再次拉取并删除了所有那些无法访问的提交

I know this is not a good solution but I did a filter-branch and ended up with duplicate, unreachable commits which didn't belong to any branch but couldn't remove them automatically, I tried every single solution posted here, absolutely nothing worked. So I pushed to a remote repository (github), deleted my local repository and then pulled again and got rid of all those unreachable commits

淡忘如思 2024-10-01 06:16:24

首先你应该考虑是否真的需要
积极删除/修剪所有无法访问的提交。

您可能收到此消息

warning: There are too many unreachable loose objects; run 'git prune' to remove them.

然后< code>git prune 似乎没有解决问题,所以你正在寻找
旋钮可以更积极地删除内容。

修剪最近提交的问题是你可以在最坏的情况下
案例(我不知道这有多大可能)损坏的东西< /a> 如果你也
与遥控器交互。

当存储库收到一个或多个推送时,就会发生活泼行为
在此过程中。罪魁祸首是服务器的广告
它的对象与处理对象的时间点不同
客户根据该广告发送的信息。

[…] 如果这些推送之一发生在 C 实际删除之前,
那么存储库最终可能会处于损坏状态。

因此,如果“松散的对象”是您的直接问题,而不是缺少磁盘
空间,或者太多的物体——那么你可以启用这个实验
功能(从 Git 2.40.1 开始):

git config gc.cruftPacks true

现在 git gc 将会打包无法访问的对象,这应该会消除该对象
警告。


总的来说,使用实验性功能似乎更安全,如果这意味着
您没有理由修剪最近无法访问的对象。

First you should consider whether you really need to
aggressively delete/prune all unreachable commits.

You might have gotten this message:

warning: There are too many unreachable loose objects; run 'git prune' to remove them.

And then git prune didn’t seem to solve the problem, so you are looking
for knobs to delete things more aggressively.

The problem with pruning recent commits is that you can in the worst
case (I don’t know how likely this is) corrupt things if you also
interact with a remote.

The racy behavior occurs when a repository receives one or more pushes
during this process. The main culprit is that the server advertises
its objects at a different point in time from processing the objects
that the client sent based on that advertisement.

[…] If one of these pushes happens before C is actually removed,
then the repository can end up in a corrupt state.

So if “loose objects” is your direct problem—rather than lack of disk
space, or just too many objects—then you can enable this experimental
feature
(as of Git 2.40.1):

git config gc.cruftPacks true

Now git gc will pack unreachable objects, which should get rid of that
warning.


It seems on balance safer to use an experimental feature if it means
that you won’t have a reason to prune very recent unreachable objects.

萌面超妹 2024-10-01 06:16:24

我正在寻找这个问题的解决方案并使用一些我的私人仓库。然后我经历了有趣的行为。

我有镜像克隆的存储库(clone --mirror),并在其中运行其他答案中提到的命令。根本没有孤立的提交。然后我将该镜像存储库 (push --mirror) 推送到 GitHub(到新的空白存储库,以免弄乱原始存储库),实际上没有这些提交。

更多详细信息和示例此处,我使用 OP 的存储库进行演示。

I was looking for solution to this question and playing with some my private repo. Then I experienced interesting behavior.

I have mirror cloned repo (clone --mirror) and inside of it run commands mentioned in other answers here. There were no orphaned commits at all. Then I pushed that mirror repo (push --mirror) to GitHub (to new blank repo to not mess with the original one) and indeed there were no these commits.

More details and example here where I used OP's repo for demo.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文