When I last merged a development branch of add-rel-lightbox into the master branch and realised that I'd not finished testing the changes, it was off to the internet to find out how to undo a merge. After a couple of goes at git revert -m 1 refused to do anything, and a little more searching, I found out that there are two types of merge: a Commit Merge and a Fast-Forward merge.

Once it was clear what happened during a merge, it was much easier to see how to go about undoing the change.

Commit Merge

Commit Merge Commit Merge

When development has taken place on both branches before the merge operation, git has to create a new commit that mixes the changes.

Git will automatically try to make a commit, but using git merge -n (branch_name) or having merge conflicts will leave you to make a manual commit.

Fast-Forward Merge

Fast-Forward Merge Fast-Forward Merge

If there's only development in one branch, then when you make the merge, git will just update the head position for the receiving branch. The merging branch is then a sub-set of the history if the recipient branch. <!-- more -->

No Fast-Forward Merge

-no-ff Merge -no-ff Merge

A special form of a commit merge; git commit -no-ff (branch_name) will force a commit merge, even if it is possible to make a fast-forward merge.

Undoing Merges

If the merge hasn't been pushed remotely yet, then it's fairly straight forward to undo, if the merge has already been published remotely, then it's best to issue a revert: a new commit that reverts a previous one, so as not to upset the history of any other pulled clones.

For a commit merge that hasn't been committed yet,

git reset HEAD

will clear the Staging Area of any changes (Warning: git reset --hard HEAD will also clear the Working Directory of any changes compared to the HEAD commit).

If the merge commit has already been made, you can move the tip of the receiving branch back to it's previous position. For the example above:

git checkout master git reset B

will set the tip of the master branch back to commit "B" and the merge commit "F" will be ignored and eventually thrown away (use the sha of actual commit as appropriate).

For the Fast-Forward Merge, the process is the same:

git checkout master git reset B

will move the tip of the master branch back to its original position.


ProGit > Undoing Merges

Git Community Book > Basic Branching and Merging

Nvie > A Successful Git Branching Model

ProGit > Reset Demysified

StackOverflow > Revert a merge that was already pushed

Schacon > Git How-To > Revert a faulty Merge (for more complex situations)