我需要弹出并丢弃master分支中的“中间”提交。我该怎么做?


94

例如,在下面的master分支中,我只需要丢弃提交af5c7bf16e6f04321f966b4231371b21475bc4da,这是由于先前的重新设置而导致的第二次提交:

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

我怎样才能做到这一点?在此先感谢Luca

Answers:


98

底垫复归是选项。Rebase实际上会从历史记录中删除提交,因此看起来第二个提交从未存在。如果您已将master分支推送到任何其他存储库,则将是一个问题。如果您在这种情况下尝试在重新设置基准之后进行推送,则git会给您拒绝非快速合并错误。

当分支已与其他存储库共享时,还原是正确的解决方案。git revert af5c7bf16将会进行一次新的提交,该提交只会撤销af5c7bf16引入的更改。这样就不会重写历史记录,您可以清晰记录错误,其他存储库将接受推送。

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


2
万一我选择“变基”,什么是变基的正确提交?我只需要丢掉第二个……
卡·G·索韦

@ BBJ3参见mipadi的答案。
Prajwal Dhatwalia

32

如果可以选择重新设置基准,则可以重新设置基准并将其删除:

$ git rebase -i 414ceffc^

如果无法选择rebase,则可以将其还原:

$ git revert af5c7bf16

如果我得到的是“ git rebase 414ceffc”,这是较旧的第四次提交,我也不会同时松开第三个e6523和第一个60b41吗?
卡·索瓦

3
@Luca G. Soave:仅当您明确git rebase要求删除提交(通过rebase以交互方式运行并删除其条目)时,您才“丢失”提交。
mipadi

谢谢mipadi,即使你们两个说了同样的话,我还是要对JCotton的广泛解释投我赞成的票……再次感谢。
卡·索瓦

29

尽管大家都对此处收到的原始答案表示赞赏,但我并没有发现它们能够令人满意地回答问题。如果您发现自己需要删除某个提交或从历史记录的中间删除一个提交的情况,那么我建议:

  • 在包含所有提交的分支的头上创建一个新分支,并切换到该分支。
  • 将新分支还原到要从中开始新基础的点。
  • 然后,(这是关键点)从原始分支到新分支,挑选您真正想要应用的后续提交,然后跳过不再想要的提交(即您要删除的提交)。
  • 如果需要,可将原始分支重命名为表明其旧代码的名称,然后将新分支重命名为原始分支。
  • 最后,将您的更改推送到远程存储库(如果使用的话)。您可能需要使用“强制推送”。如果您的协作者在拉动修订版时遇到问题,那么对他们来说,最简单的方法是从远程源再次克隆存储库。无论如何,如果您将提交从历史记录中剥离出来,您可能想与他们交谈!

以下是有关Cherry Picking的信息: 用git来选择一次commit是什么意思?

这是使用Tortoise Git进行操作的一些方法(就像我刚才所做的一样)。使用gui实用程序进行此类操作绝对容易! 使用TortoiseGit挑选樱桃


6
这应该是最佳答案!
MadOgre

一种很好的选择方式,当您要“跳过”多个提交时,此解决方案甚至更好。
约翰尼·威勒

没有真正解决原始问题。尽管建议的解决方案有效,但它耗时/笨拙得多,并且IMO没有带来任何好处。如果分支已经被推送(并在野外使用),那么恢复策略可能就是答案。如果没有,我将使用交互式的基础,并删除有问题的提交。如果它被推送了,但是我们知道它未被任何人使用,那么您仍然可以通过重新设置基础然后强制执行来摆脱困境。
raduw
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.