How to Undo a Merge in Git

How to Undo a Merge in Git

Hugo Escafit

Merging is essential to every developer's workflow in Git. Without merging, your codebase would wither as contributors come up empty-handed when it comes time to mix their work in with what has already been published. Merging makes this all possible.

But merging can also make for a mean headache if you make a mistake. A bad merge can detract from your project’s historical continuity, confuse fellow contributors, and potentially slow down development for all involved. That’s precisely why every Git-using dev should be well-versed in undoing bad merges, both locally and remotely.

There are multiple ways to do many things in Git, and merge reversals are no exception. You can end up hopelessly lost and confused about choosing the best command or technique to preserve important work while minimizing the effects of mediocre merge results—especially without the right information on the topic. To learn how to handle this important part of Git project management, keep reading.

How to undo a Git merge

To merge is one thing; to undo a merge is another. Undoing a merge is a multifaceted process, but it does not need to be particularly complicated. Let’s look at all of the things you should be aware of to make your next merge catastrophe go away.

Sometime, break-up is the best thing to do...

First of all, you should know that there are three commands that you can turn to in order to get Git back the way you want it after a messy or otherwise incorrect merge operation. These are:

  • git merge --abort
  • git revert
  • git reset

Let's see how they work.

Aborting a merge ❌

Each of these commands has its strengths and weaknesses, not to mention its own gotchas to reason about before you start using it. For example, git merge --abort actually allows you to stop a merge in its tracks once you’ve discovered it has troublesome conflicts. It makes for a perfect solution just after you’ve typed git merge at the most inopportune moment imaginable. So long as your work has not been committed, you’re free to abort your last merge without leaving much of a trace. This can be a grand thing or a bit of a problem in its own right, depending on your needs and project guidelines. Uncommitted worktree changes that were there when the merge process first began can actually end up lost for good if you’re not careful. You’ll need to either stash or commit any floating changes before you go through with a merge abort to avoid losing important work.

Using git merge --abort after a bad merge can help you escape a problematic conflict resolution process. However, that does not make it suitable for all Git merge undo emergencies. The other two commands mentioned above should each have their place in your repertoire to facilitate local and remote merge undoing, respectively.

Undoing a merge after push

Once your merge has been pushed out to a remote branch, it can become a bit more complicated to undo on a technical level as Git must reconcile more changes and differences than it had to in your local environment. Luckily, Git is more than capable of doing this (and more) with the revert command. Revert can be used to roll back a single commit or a full merge as needed. To undo a merge in Git once it has been pushed, you can use:

git revert -m 1 <sha-of-target-commit>

The -m 1 option specifies the parent (branch) number as the one you want to keep, and the hash value directs git to the exact point you would like to revert to. Even better, once changes have been made, you can revert the revert itself by referencing its id in git revert <sha-of-revert>.

All those operations create a new commit that you can push to your remote, as needed.

Undoing local merge

Undoing a merge you just made in your local environment is one of the easier operations of this type that you can perform. All you need is the git reset command, and you can get right back on track with your work. However, there are a few hidden gotchas in this deceptively simple command that you should definitely know about before proceeding.

To start, you’re going to need to run a git stash command to protect any local changes within your working copy. These changes would otherwise end up lost after the reset, potentially wasting quite a lot of work in the process. With your stash operation concluded, you can proceed with the reset. To make it work, you will need to set the --hard option flag right after the command name. Next, to the right of the --hard flag, you will need to include the unique hash of whatever commit came before your merge. In the end, your command should look something like this:

git reset --hard <sha-of-last-commit>

This works just fine for most local merge meltdowns, but there is at least one more approach you should know about: Using git reset --hard HEAD~1. To understand this variation, we can interpret HEAD~1 as a reference to the commit just one step before the current HEAD revision. This makes it possible to target commits that you don’t have any hash references for. You can replace 1 by the number of commits you want to go back to.

How Mergify can help 💪🏼

Managing merges can be difficult—even those who know what they’re doing with Git and GitHub may ultimately find the merge process hobbled by tedium and bottlenecks requiring frequent manual intervention. With Mergify, you can make all of these kinds of problems go away.

Mergify gives your team the power of automation, making tedious tasks such as pressing that merge button on GitHub a walk in the park. Imagine saving loads of time on the drudgery of queueing and merging as well as carving out quality moments away from rebasing, labeling, and commenting tasks. Now imagine making every one of these concerns a breeze with purpose-built automation that just works.

Interested? Schedule a demo today to discover what Mergify can do for you.