删除旧的Git提交记录。

128

我很新手git,想知道是否可能像这样做?

>git log --pretty=oneline --abbrev-commit
2f05aba Added new feature
3371cec Fixed screw up    <-- I want to remove this
daed25c Screw up          <-- and remove this.
e2b2a84 First.                So it's like they never happend.

这可能吗?


2
未来的访问者注意:我认为有必要指出,对这个问题的答案在其解释上存在分歧。有些人假设“提交从未发生过”,因此更改不会被保留(“丢弃”)。其他人则认为应该保留删除的提交中的更改(“压缩”或“修复”)。请根据您所需的内容选择您的答案。 - TTT
6个回答

113
如果你真正想要删除它们(将它们从历史记录中擦除,永远不再显示),你可以运行变基(rebase):
git rebase -i HEAD~4

然后,只需删除(或注释掉)与您希望删除的提交相对应的行,就像这样:

pick 2f05aba ... #will be preserved
#pick 3371cec ... #will be deleted
#pick daed25c ... #will be deleted
pick e2b2a84 ... #will be preserved

2
我是github的新手,之后如何推送更改(当我点击同步时,它只会还原我所做的)。我想我明白了:git push origin HEAD --force - Nicolas Thery
我假设这只在当前的Git存储库中起作用,不会更改任何上游/其他Git节点的内容? - Alexander Mills
2
只要你不推送它(如果你这样做了,就必须像 Angry Dan 说的那样添加 --force 标志),它就不会改变上游任何内容。 - Shathur
2
ddrop 是从历史记录中删除提交的命令。 - Abandoned Cart
1
@NicolasThery,既然没有人给你一个诚实的答案:同步按钮不起作用的原因是因为它在后台执行了很多垃圾操作,试图将你的分支“恢复”到与仓库匹配(它运行了大约15个单独的git命令)。如果你确定没有人克隆了你的仓库,只需从终端运行git push --force即可。否则就放弃吧,接受错误。 - aggregate1166877
显示剩余2条评论

77

使用 git rebase 是可以实现的。尝试执行以下命令:

git rebase -i HEAD~4

接下来,在你的编辑器中按照交互式说明操作。在第一步中,你需要“压缩”提交记录。应该看起来像这样:

pick 2f05aba ... will be preserved
squash 3371cec ... will be squashed with daed25c
squash daed25c ... will be squashed with e2b2a84
pick e2b2a84 .. will contain this and 3371cec and daed25c

在第二步中,您可以编辑提交消息。


42
这个问题不是关于压缩(commit squashing),而是关于删除(commits deletion)吧? - Richard
4
@Stony:嗯,你也可以删除它们。但从原始帖子的提交注释中(“搞砸了”和“修复搞砸了”),我认为其中一个是在撤销另一个,因此你也可以将两个合并为一个。 - Deve
我认为那只是你个人的假设。正如@Richard所提到的,这是关于删除的问题。 - DarkTrick

20

现在有一个新选项drop用于完全删除提交的git交互式变基。首先运行:

git rebase -i HEAD~4

然后将 pick 替换为 drop,以删除需要丢弃的提交:

pick 2f05aba ... #will be preserved
drop 3371cec ... #will be dropped
drop daed25c ... #will be dropped
pick e2b2a84 ... #will be preserved

这对我在Fedora上使用以下版本有效:

$ git version
git version 2.21.0

4

Squash在生成单个哈希下合并提交列表时非常有用,但是如果您想要将三个独立的提交合并为一个最终输出,我建议使用fixup

git rebase -i HEAD~4

pick 2f05aba ... will be preserved
fixup 3371cec ... will be merged with daed25c
fixup daed25c ... will be merged with e2b2a84
pick e2b2a84 .. will include 3371cec and daed25c, but only the commit message of e2b2a84

您可以在交互式变基UI的命令列表中找到更多信息。

1

简短版: 一个命令即可解决问题:git rebase 3371cec 2f05aba --onto e2b2a84

详细版:

注意,其他答案对于问题的解释存在分歧。如果您希望保留要删除的提交中所做的更改,则可以使用交互式变基(rebase -i),然后将这两个提交的 "pick" 更改为 "squash" 或 "fixup"。

如果您希望删除这些提交,就好像它们从未发生过一样,并且也不保留它们的更改,则同样可以使用交互式变基,在指令列表中将这两个提交的 "pick" 更改为 "drop",或者注释掉这些行,或者删除这些行,所有这些操作都会达到相同的效果。

请注意,如果一个或多个提交被分组在一起,则可以使用一行变基命令,而无需使用交互模式。例如:

# Suppose you have: A-B-X-Y-C
# and you wish to remove X and Y:

git rebase Y C --onto B
# or (equivalent)
git rebase C~1 C --onto C~3
# both would result in: A-B-C'

# with this question's commit IDs:
git rebase 3371cec 2f05aba --onto e2b2a84
# or (equivalent)
git rebase 2f05aba~1 2f05aba --onto 2f05aba~3

很多时候,我只需要从功能分支的线性历史记录中删除单个提交。假设要删除的提交ID是 X,而 X 之后的提交ID是 K(你想要“保留”的提交)。
git rebase K~1 K --onto K~2

请注意,K~2 表示你希望删除的连续提交数量加一。如果您想删除 2 个提交,则可以使用 K~3,如果要删除 10 个提交,则为 K~11

-2

大多数时候我都会遇到同样的问题,我使用以下命令删除旧的提交并与服务器同步

git reset --hard HEAD~1
git push -f

小提示: HEAD~1 将删除最后一次提交 HEAD~5 将删除最近的 5 次提交 push -f 是强制推送,以便在服务器(github/bitbucket/其他)上的副本也被删除


1
问题希望在删除其他提交后保留一个提交。因此,这个答案是不正确的,因为那个提交将会丢失。 - TTT

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