如何在我的主分支中弹出并删除一个“中间”提交?

100
例如,在下面的主分支中,我需要丢弃仅限于提交af5c7bf16e6f04321f966b4231371b21475bc4da,它是由先前的rebase引起的第二个提交:
commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

我需要维护:

  • 第一个提交:60b413512e616997c8b929012cf9ca56bf5c9113,
  • 第三个提交:e6523efada4d75084e81971c4dc2aec621d45530,以及
  • 最后一个提交:414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22。

只需“丢弃”第二个提交af5c7bf16e6f04321f966b4231371b21475bc4da。如何做到这一点?

3个回答

108

Rebase(变基)revert(还原)是两种选择。Rebase将实际上从历史记录中删除提交,因此看起来第二个提交从未存在过。如果您已经将主分支推送到其他任何存储库,则会出现问题。在这种情况下尝试推送后,git会给出拒绝非快进合并的错误。

当分支与其他存储库共享时,还原是正确的解决方案。 git revert af5c7bf16 将创建一个新的提交,只需撤消af5c7bf16引入的更改即可。这样,历史记录不会重写,您可以保留有关错误的清晰记录,并且其他存储库将接受推送。

这是一种很好的擦除方式: git rebase -i <commit>^ 。这将使您跳转到要删除的提交之前的提交。交互式编辑器将显示自该点以来的所有提交列表。您可以选择、压缩等。在这种情况下,删除要删除的提交行并保存文件。Rebase将完成其工作。


2
如果我选择Rebase,应该选择哪个正确的提交进行Rebase?我只需要删除第二个提交... - Luca G. Soave
@BBJ3 请查看 mipadi 的回答。 - Prajwal

37

如果可以使用 rebase 选项,你可以进行 rebase 并且只需放弃它:

$ git rebase -i 414ceffc^

如果rebase不是可选项,你可以简单地撤销它:

$ git revert af5c7bf16

如果我使用“git rebase 414ceffc”命令来回退到第四个提交,那么第三个提交e6523和第一个提交60b41也会被删除吗? - Luca G. Soave
3
只有当你明确告诉git rebase删除提交(通过在交互模式下运行rebase并删除其条目)时,才会“失去”一个提交。 - mipadi
感谢 mipadi,我基本上是因为他做了详尽的解释才投票给 JCotton 的,即使你们两个说的是同样的话...再次感谢。 - Luca G. Soave

31
尽管原回答在这里得到了很多好评,但我并没有完全找到它们令人满意地回答问题。如果您发现自己需要从历史记录的中间删除提交或一组提交的情况下,以下是我的建议:
  • 从包含所有提交的分支头部创建一个新分支并切换到它。
  • 将新分支恢复到您想要从中开始新基础的点。
  • 然后(这是关键点)从原始分支中向新分支拾取您实际想要应用的后续提交,并跳过您不再需要的提交(即您要删除的提交)。
  • 如果需要,将原始分支重命名为指示其为旧代码的名称,然后将您的新分支重命名为原始分支的名称。
  • 最后,将更改推送到远程 repo(如果使用)。您可能需要使用“强制推送”。如果您的协作者在拉取修订版本方面有问题,他们可能最容易从远程源再次克隆存储库。无论如何,如果您正在从您的历史记录中删除提交,您可能需要与他们交谈!

这里有有关 Cherry Picking 的信息: Git 中 Cherry Picking 指什么?

这里有一些关于使用 Tortoise Git(就像我所做的那样)进行操作的信息。对于这些操作,使用 GUI 实用程序肯定更容易! 使用 TortoiseGit 进行 Cherry Pick


6
这应该是最佳答案! - MadOgre
使用cherry pick的好方法,当您想要“跳过”多个提交时,这种解决方案甚至更好。 - Johnny Willer
1
并没有真正回答原问题。虽然建议的解决方案可行,但更加耗时/笨拙,而且在我看来并没有带来任何好处。如果分支已经被推送(并在实际中使用),那么还原策略可能是正确的答案。如果没有,交互式变基并删除有问题的提交是我会使用的方法。如果它已经被推送,但我们知道它没有被任何人使用,你仍然可以通过变基后强制推送来解决。 - raduw

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