我需要弹出并清除主分支中的“中间”提交。我该如何做呢?

例如,在下面的主分支中,我只需要删除提交的 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

“扔掉”只是第二次提交 F5c7bf16e6f04321f966b4231371b21475bc4da

我该怎么做? 先谢谢你 卢卡

45165 次浏览

If rebase is an option, you can rebase and just drop it:

$ git rebase -i 414ceffc^

If rebase is not an option, you can just revert it:

$ git revert af5c7bf16

Rebase or revert are the options. Rebase will actually remove the commit from the history so it will look like that second commit never existed. This will be a problem if you've pushed the master branch out to any other repos. If you try to push after a rebase in this case, git will give you a reject non fast-forward merges error.

Revert is the correct solution when the branch has been shared with other repos. git revert af5c7bf16 will make a new commit that simply reverses the changes that af5c7bf16 introduced. This way the history is not rewritten, you maintain a clear record of the mistake, and other repos will accept the push.

Here's a good way to erase: git rebase -i <commit>^ That takes you to the commit just before the one you want to remove. The interactive editor will show you a list of all the commits back to that point. You can pick, squash, etc. In this case remove the line for the commit you want to erase and save the file. Rebase will finish its work.

Despite all the credit the original answers received here, I didn't quite find them to satisfactorily answer the question. If you find yourself in a situation where you need to remove a commit, or a collection of commits from the middle of the history, this is what I suggest:

  • Create a new branch off the head of the one containing all the commits and switch to it.
  • Revert the new branch back to the point you want to start a new base from.
  • Then, (here's the key point) cherry pick the subsequent commits you actually want to be applied after that from the original branch to the new one, and skip the commits you don't want anymore (i.e. the ones you are deleting).
  • If desired, rename the original branch to something indicating it's old code, and then rename your new branch what the original one was called.
  • Finally, push your changes to your remote repo (if using one). You'll probably need to use a "forced push". If your collaborators have issues pulling the revisions, it might be easiest for them to just clone the repo again from the remote source. One way or another, you'll likely want to talk to them if you are ripping commits out of the middle of your history anyway!

Here's info on Cherry Picking: What does cherry-picking a commit with git mean?

Here's some on doing it with Tortoise Git (as I just did). It's definitely easier to use a gui utility for these sorts of operations! Cherry pick using TortoiseGit