Revert the Revert and Avoid Conflicts

Let me tell you my story about git, conflicts and reverts.

On a project, I start a feature on a branch, open a pull request towards master branch and merge it by mistake before finishing my code.
No git story would be complete without drawings.

Mistake

Oops!

What is the clean way to fix my mistake?

My first idea is to quickly push --force to master branch to cancel the merge when nobody is looking.
I read on the Internet that this is a bad idea on a shared branch.
Therefore, I decide to do it the “clean way”, which in my case is revert.

I can revert manually on the command-line, or thanks to GitHub directly from the merged pull-request!

Easy

My git history now looks like this:

Everything back to normal

Now is the time to deploy my code.

I can’t merge my feature, what’s going on?

I’ve added my missing commit, I reopen a pull request and see this on GitHub:

What did I do wrong?

How does a merge commit work?
A merge commit takes the diff between the common ancestor and the first parent commit and the diff between the common ancestor and the second parent commit and applies them together.

Sounds simple

Let’s look at my git history:

I knew I should have just pushed --force...

Now suppose my feature introduced a new file script.sh, and that I modified it in my feature branch after the revert.

Let’s see what this means:

Eurêka!

That’s great!
I understand that the revert commit is the culprit here.
But how do I get back on my feet and merge my feature?

Solution: revert the revert!

I want to avoid the revert commit in my merge, therefore I rebase my feature branch on master branch so that the merge commit common ancestor is after the revert commit.

Did that work?

I can’t apply my feature commit on master branch because script.sh does not exist.
I need a commit before that reinstates script.sh and that is not already merged into master branch.

That’s where the magic occurs, I revert the revert commit, and then cherry-pick my new commit.
Let’s see this in action:

Complete solution

It’s working, at last!

Epilogue

This solution requires a good visualization of the situation to understand and implement it.
Always draw when you have a problem with git.

The best way to avoid all this work is to avoid the mistake in the first place:
be careful when merging your pull requests.

I rejected the push force method because it is dangerous, but my solution is quite thorny!
There are situations where push force is indeed a good choice, even on a shared branch.
Be sure to warn your collaborators and explain to them the necessary steps to recover from it if needed.


You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.

Join Us

  • Florian

    Thank you for the article.
    When I have conflicts due to a revert, I prefer to rename the commits (amend them), so they have a new commit ID and they are not considered as already present on master branch. It seems less hackish to me.
    Do you see a risk in using this method?

  • Tristan Roussel

    I’ve used this method in the past successfully. The only problem you may have is if the accidentally merged history is complex, you have to remember to modify every commit in the chain. Reverting the revert has the benefit of getting to the same result in only one commit, and in my opinion to be clearer in terms of intent in your git history.

    Either way, the history will be a mess and push force is much easier.