列出和删除没有分支的 Git 提交(悬空?)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3765234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Listing and deleting Git commits that are under no branch (dangling?)
提问by Samer Buna
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.
我有一个 Git 存储库,其中包含大量不在特定分支下的提交,我可以git show
,但是当我尝试列出包含它们的分支时,它什么也没报告。
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:
我认为这是悬空提交/树问题(由于 -D 分支),所以我修剪了 repo,但在那之后我仍然看到相同的行为:
$ 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?
该提交的确切状态是什么?如何列出处于类似状态的所有提交?如何删除这样的提交?
采纳答案by Aristotle Pagaltzis
No output, nothing dangling (right?)
没有输出,没有悬空(对吧?)
Note that commits referred to from your reflog are considered reachable.
请注意,从您的 reflog 引用的提交被认为是可访问的。
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.
通过--no-reflogs
说服git fsck
将它们展示给您。
How can I delete commits like those?
如何删除这样的提交?
Once your reflog entries are expired, those objects will then also be cleaned up by git gc
.
一旦您的 reflog 条目过期,这些对象也将被git gc
.
Expiry is regulated by the gc.pruneexpire
, gc.reflogexpire
, and gc.reflogexpireunreachable
settings. Cf. git help config
.
到期由调控gc.pruneexpire
,gc.reflogexpire
和gc.reflogexpireunreachable
设置。参见 git help config
.
The defaults are all quite reasonable.
默认值都很合理。
回答by tarsius
To remove all dangling commits and those reachable from the 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:
git gc
删除无法访问的对象(提交、树、blob(文件))。如果某个对象不是某个分支的历史记录的一部分,则该对象是无法访问的。其实有点复杂:
git gc
does some other things but they are not relevant here and not dangerous.
git gc
做了一些其他的事情,但它们在这里无关紧要,也不危险。
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".
不到两周的无法访问的对象不会被删除,因此我们使用--prune=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.
也可以通过 reflog 访问对象。分支记录了一些项目的历史,而reflogs 记录了这些分支的历史。如果您修改、重置等,提交将从分支历史记录中删除,但 git 会保留它们,以防您意识到自己犯了错误。Reflogs 是找出在分支(或 HEAD)上执行了哪些破坏性(和其他)操作的便捷方式,可以更轻松地撤消破坏性操作。
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
.
因此,我们还必须删除引用日志以实际删除从分支无法访问的所有内容。我们通过使--all
reflog过期来做到这一点。再次混帐保持一个位reflogs的保护用户,所以我们不得不再次告诉它不这样做:--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.
由于我主要使用 reflog 从破坏性操作中恢复,因此我通常使用--expire=now
它来完全消除 reflog。
回答by jakub.g
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.
我删除了标签git tag -d <tagname>
并重新进行了清理,旧的提交消失了。
回答by sehe
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042
probably just needs to be
可能只需要
git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042
to also report on branches from remotes
还报告来自遥控器的分支
回答by Andrew Larsson
I had a similar issue. I ran git branch --contains <commit>
, and it returned no output just like in the question.
我有一个类似的问题。我跑了git branch --contains <commit>
,它没有像问题一样返回任何输出。
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.
我的提交仍然可以使用git show <commit>
. 这是因为其分离/悬挂“分支”中的其中一个提交被标记。我删除了标签,再次运行了上面的命令,我很成功。git show <commit>
返回fatal: bad object <commit>
- 正是我需要的。希望这可以帮助像我一样陷入困境的其他人。
回答by Lei Zhao
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.
我不小心遇到了同样的情况,发现我的 stash 包含对无法访问的提交的引用,因此可以从 stash 访问假定的无法访问的提交。
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
回答by dublev
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).
git gc --prune=<date>
默认修剪两周前的对象。你可以设置一个更近的日期。但是,创建松散对象的 git 命令通常会运行 git gc --auto(如果松散对象的数量超过配置变量 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.
您确定要删除这些提交吗?gc.auto 的默认设置将确保松散对象不会占用不合理的内存量,并且将松散对象存储一段时间通常是一个好主意。这样,如果你明天意识到你删除的分支包含你需要的提交,你可以恢复它。