如何在git中永久删除一个孤立的提交?

48

我有一些本地提交(commit)不在任何分支上,我想要删除它们。我不想 rebase 它们,而是真的想要删除它们,并且失去与这些 commit 相关的所有内容。

有没有命令可以这样做?

到目前为止,我已经尝试了许多人建议的交互式变基(interactive rebase),但它只是移动 commit,而不是删除它们。我还尝试使用 reflog delete 命令,但我无法弄清楚如何将特定的 commit Id 传递给该命令。

这是工作树:

o [master] Commit #6  
|  
o Commit #5  
|  
| o Commit #4  
|/  
o Commit #3  
|  
o Commit #2  
|  
o Commit #1  

我想要物理删除提交记录 #4。


你能详细解释一下“移动提交”是什么意思吗? - greg0ire
@greg0ire 嗯,提交仍然存在,但是它与其他内容相关联了。这就是rebase所做的:更改提交的父节点...是吧? - FMaz008
在交互式变基中,您需要完全删除包含要删除提交的行。 撤消提交只是创建一个新的提交,应用指定提交的反向差异。 这只会添加另一个您必须删除的提交。 尝试变基并完全删除该行。 - Brian Riehman
@Brian Riehman,嗯。您有特定的命令来执行您告诉我的操作(真正物理删除提交)吗?请注意,我只有一个commitId... - FMaz008
当您运行交互式变基并打开文本编辑器时,只需删除要删除的提交行。Git将重新应用所有其他提交,并且该提交将不再可达到当前分支。然后,该提交将在一个月后被Git的垃圾回收清除。 - Brian Riehman
显示剩余3条评论
3个回答

61
如果提交未被任何东西引用,它将在一段时间后被git的垃圾回收机制清除。
如果您想提前强制执行清除,请使用git gc --prune=now --aggressive命令。

1
我之前在一个分支上,做了一个提交,然后用 GUI 撤销了这个提交(我认为这相当于硬重置)。现在我的提交已经不在任何分支上了,但提交仍然是一个分支的“父级”。我尝试了命令,但我仍然有一些无用的提交 :( - FMaz008
1
在 Git 中还原提交不仅仅是将提交撤销,而是应用提交的反向操作。如果您不想要的提交位于分支的顶端,请使用 git reset --hard shaOfLastGoodCommit。这将删除错误的提交并将您的分支指针移动到最后一个良好的提交。 - Andy
1
根据您的图形,对于提交#4仍然可见,必须有某些内容(标签,分支,另一个提交...)指向它。git log --graph --decorate --all --oneline显示了什么?是否有任何装饰符与该提交在同一行上?是否有任何上面的提交? - Andy
git log --graph --decorate --all --oneline 返回提交 #1、2、3、5、6。提交 #4 的 commitId 没有显示。 - FMaz008
3
由于您最近曾经检出过该提交,因此它很可能仍在HEAD的reflog中,这意味着git无法对其进行垃圾回收。没有必要非常着急地删除所有提交的副本,因为它已经不再任何分支上可达,但如果您真的想这样做,可以修改reflogs。请参阅git help reflog - amalloy
显示剩余10条评论

7
为了完全删除一个提交,你需要删除所有对它的引用,然后强制进行垃圾回收。如果您仍然有指向该提交的分支,请先删除这些分支。接下来,您需要从reflog中清除该提交,reflog默认保留过去90天内访问的每个提交的引用(请使用该提交哈希的前8个字符替换[commit-hash])。
git reflog --all | grep [commit-hash] | cut -d' ' -f2 | cut -d':' -f1 | tac | xargs git reflog delete

我使用 tac 命令反转删除顺序,因为如果提交在 reflog 中出现多次,删除一个条目会导致其后面的所有条目都要向前移动。

最后,强制进行垃圾回收:

git gc --prune=now --aggressive

完成这一步之后,git show [commit-hash]将不再显示该提交记录,因此您将知道它已被真正删除。


1
git reflog 命令需要使用 --all 标志,否则它只会显示 HEAD 的 reflog 而不是每个单独分支的 reflog,而 Git 也存储了这些信息:git reflog --all | grep [commit-hash] | cut -d' ' -f2 | cut -d':' -f1 | tac | xargs git reflog delete - Jimmy He

3
要删除一个提交,你只需确保它不再是任何分支的一部分。也就是说,对于存储库中的每个分支,确保错误提交不再是定义该分支的父子提交链的一部分。如果你找到这样的一个分支,要么删除它,要么更改其历史记录,使其不再包含有问题的提交。
一旦满足了上述条件,错误提交最终会被垃圾回收。

只有在自动垃圾回收的系统上才能实现。 - Phil

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