Git — fix commits mistakenly pushed to master branch

Nhat Cuong / Nathan
an engineer / a reader / a guy
4 min readDec 20, 2016
Photo by Simon Matzinger on Unsplash

You can make mistakes using Git, especially in your early days with it. Fixing these mistakes can be a struggle if you don’t master it well, and a bad fix can give you bad surprises in the future. This article shows the technique and understanding about how to fix the commits mistakenly pushed to master branch.

The context

Let’s assume you share a master branch with your team mates and work currently on a feature branch. At a moment of the day, you think you are on your feature branch, so you code, make 2 commits (named f2 and f3), and push them to your remote repo. But only then you realized that you are actually on master, and some commits of your unfinished work are now on the team’s remote master branch. How to get out gracefully of this situation?

Requirements of a good solution

  • Code from the commits mistakenly pushed must be cleaned out from master immediately.
  • These commits must be retrieved in the feature branch, now.
  • Later, when you finish developing your feature branch, the merge into master must be done seamlessly, as if there has never been any mistaken commits.

Step 1: Merge master into feature

Use merge, not cherry-pick. Cherry-pick can cause conflicts in the future merge. If you have unrelated commits on the master branch, it does not do any harm if to merge them into the feature branch; these codes are meant to be merged together sooner or later.

git checkout feature
git merge master

And you now have f2 and f3 in your feature branch. But they still are on master branch, too.

Step 2: The first revert

We are now using git revert on the master branch.

git checkout master
git revert --no-commit f3
git revert --no-commit f2
git commit -m 'revert f2 and f3'

So now f2 and f3 are reverted from master branch. Is the problem solved? Not yet, and here's why:
An important thing to know about git revert is that it does not remove f2 and f3 from the master branch. It actually adds a commit that undoes f2 and f3 (totally different!), which makes master branch to be ahead of feature branch by the revert commit r1.

If you just continue working and making commits to feature branch, you might have conflicts when you try to merge it into master. More importantly, you might lose some part of your work doing the merge due to this first revert.

Step 3 (final): The second revert

We are going to merge master into feature branch (again), and then make a second revert commit there.

git checkout feature
git merge master
git revert r1 -m "bring back code from commits f2 and f3"

The fix is done now.
So we did a revert on r1 (the first revert). Let's call this second revert r2. In the picture below, I added a further commit (f4) to feature branch that represents further work on feature branch. As you can see, feature branch is ahead of master by 2 commits: r2 and f4. The day you finish working on feature branch and merge it into master, the first revert r1 in master will no longer cause troubles (conflicts, code disappearing) because the second revert r2 handles it. The merge will be done seamlessly.

Of course it is redundant having 2 merges. You can proceed by doing the revert r1 first, and then merge master into feature branch, which will save you a merge. I did not do that optimization in this article for clarity’s sake.

A simpler “solution” that you should never do

You can be tempted to use git reset on your local master branch and then “force push” it to the remote branch. Let’s name m0 the commit on your local branch master before f2 and f3.

git reset --hard m0
git push origin master --force

This rewrites the remote history, which is very dangerous. Some work of other team members on master might be erased. And even if no other commits have been pushed after m0, there's always a risk that someone already pull master at f3 and based his work on it. When this person merges his work to the remote master, f2 and f3 will be retrieved into the remote master and probably in an unoticed way.

--

--