zzy
zzy

Reputation: 791

Use `git rebase` to remove a commit in the middle

I'm trying to undo a commit in the middle while keeping the following ones unchanged. I have thought it might be impossible before finding these posts: Post 1 & Post 2. (The ultimate goal might be duplicated but I indeed didn't have it work. I apologise for that.)

Unfortunately, I'm still stuck in how to use git rebase -i properly. I created a sample repo as following:

commit cc2576365a9716bb9f96e195e599190d3c70fba0
Author: zzy
Date:   Sun Jul 17 14:30:53 2016 -0400
commit #3

commit 11d9f8fdc69be8b4530e4b70c9661b4e34287afe
Author: zzy
Date:   Sun Jul 17 14:30:36 2016 -0400
commit #2

commit 4770e08eb54d0d582bd4b391f2361a328b417cdf
Author: zzy
Date:   Sun Jul 17 14:29:58 2016 -0400
commit #1

Each commit adds a new line at a file called a (see a's content below):

After commit #1

1

After commit #2

1
2

After commit #3

1
2
3

Now I intend to remove commit #2, and the a should look like:

1
3

I tried the command as git rebase -i 11d9f8fdc69be8^ and get the text file as:

pick 11d9f8f commit #2
pick cc25763 commit #3

I deleted the first line, only keeping commit #3 and exited the file. But I get the following error:

error: could not apply cc25763... commit #3

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
Could not apply cc2576365a9716bb9f96e195e599190d3c70fba0... commit #3

And the file a becomes:

1
<<<<<<< HEAD
=======
2
3
>>>>>>> cc25763... commit #3

I'm confused why 2 is still here and why there are conflicts. Could anyone help me to get the expected result? Thanks in advance!

Upvotes: 0

Views: 1338

Answers (1)

Ajedi32
Ajedi32

Reputation: 48418

Basically, since both commit #2 and commit #3 changed lines that were very close to each other in the same file, git doesn't know quite how to "replay" the changes in commit #3 now that commit #2 is no longer present, so you're getting a conflict.

Within the file that contains the conflicts, you see this:

<<<<<<< HEAD
=======
2
3
>>>>>>> cc25763... commit #3

The space between <<<<<<< HEAD and ======= shows what the file contained in that location at commit #1, before commit #2 or commit #3 were created. The space between ======= and >>>>>>> cc25763... commit #3 contains the contents of that section of the file in commit #3, after commit #2 and commit #3 were added. Git expects you to use this information to decide manually what content the new version of commit #3 should contain now that you're trying to replay it without commit #2.

Replace that whole section of the file with what you want the file to contain after commit #3 is replayed. In this case, you'd replace:

<<<<<<< HEAD
=======
2
3
>>>>>>> cc25763... commit #3

With:

3

Then, run git add a to stage these changes, and git rebase --continue to continue the rebase.

Note that you only have to do this during a rebase when conflicts are encountered. For commits which change unrelated things (e.g. if commits #2 and #3 were changing entirely different files, or completely different sections of the same file), git rebase can usually determine what changes to make automatically, and you won't encounter conflicts.

Upvotes: 2

Related Questions