Git Revert Merge Commit: A Guide With Examples

We can compromise an application by merging problematic code, whether it’s due to accidentally integrating unfinished work into the main branch or overlooking a critical bug that slipped past automated tests.

In this article, I will guide you through the process of using git revert to safely undo a merge, ensuring that the commit history remains intact and the project’s integrity is preserved.

How git revert Works

We can think of git revert as Git’s version of an undo command. However, the git revert command doesn’t delete commits or jump to a previous state of the branch. Instead, it creates a new commit that reverts the changes from a specific commit.

Illustration of how git revert works

The syntax to revert a commit with hash  <commit_hash> is:

git revert <commit_hash>

We can list the commits together with their hash identifiers using the git log command. The output of git log lists the commits from most recent to oldest commit, like so:

Identifying the commit hash with git log

For instance, to revert the commit that implements the subtract function, we would use the command:

git revert 7ba24a3e62d4d37182428ccfaa070baa222b1151

Using git revert we can undo the changes of a specific commit without affecting the commit history.

Note that git revert isn’t magical, and depending on the commit history, it can result in a conflict that has to be manually resolved.

Advantages of git revert Over Manual Changes

Why is git revert useful if we may need to resolve a conflict manually? Wouldn’t it be easier to just manually undo the changes? Let’s see its advantages:

  • Preserves history: git revert creates a new commit that undoes the changes of a specified commit while preserving the entire commit history. This helps maintain a transparent history of changes and reversals.
  • Atomic reversal: It ensures that the reversals are atomic and consistent. When we manually delete and commit changes, there’s a risk of human error. 
  • Conflict awareness: It ensures that we are alerted through conflicts if there are any integrations or changes dependent on the original commit. This might seem inconvenient, but it safeguards against unintended side effects.
  • Metadata: The new commit created by git revert includes metadata and a commit message that contextually describes what was reverted, aiding in future understanding. Without git revert, this context might be lost.

Reverting a Merge In Different Scenarios

In this section, we learn how to undo a merge. For the sake of example, we’re assuming we are merging a branch named feature into the main branch executing the command from the main branch:

git merge feature

What we learn here can be applied to any two branches by replacing the names appropriately.

Reverting a merge that has no associated commit

The git merge command doesn’t always create a new commit. A commit is created only if the main branch has diverged from the feature branch. Because git revert requires a commit to operate one, we can’t use it in this case.Explanation of what are divergent Git branches

The main and feature branches diverge when new commits are created on main that are not ancestors of the feature branch. In other words, new commits were created on main after feature was created.

If the branches haven’t diverged, when we run the command git merge feature on the main branch, Git will use fast-forward to merge. This means that it moves the HEAD of the main branch to the HEAD of the feature branch.

Illustration of what happens when we move the HEAD of the <code data-mce-selected=

We can observe that this happened by looking at the result of git merge:

How to identify that Fast-forward was used to merge

To undo such a merge, we only need to move the HEAD of the main branch back to where it was. For this, we:

  1. Identify the previous HEAD using the git reflog
  2. Reset the HEAD to the previous one using git reset --hard <previous_head>, replacing <previous_head> with the previous HEAD.

The output of git reflog will look something like this:

Finding the old HEAD reference

We can identify the previous HEAD by looking at the line that says “checkout: moving from feature to main” (it writes feature and main because those are the names of our branches). 

In this case, the previous head is fe59838. To move the HEAD of the main branch back to it and undo the merge, we then use the command:

git reset --hard fe59838

Illustration of what happens when we move the HEAD back

Reverting a merge that has an associated commit

If the main branch and feature branch have diverged, then when we merge two branches, a new commit is created, called a merge commit. 

Illustration of a merge commit

The merge commit applies the changes from one branch to another one. In this case, the changes in feature are applied to the main branch.

To revert the changes on the main branch, we use the git revert on the merge commit. This will create a new commit that undoes the changes brought into the main branch with the merge, effectively restoring the state of the main branch to what it was before the merge.

First, we need to identify the hash of the merge commit. We can do this using the git log command:

Identifying the merge commit hash

Because the merge commit has two parents, the syntax of git revert is slightly different. We need to use the -m 1 option to specify that we want to revert the changes relative to the main branch:

git revert -m 1 b8dab2c8611e324ed0d273133987415350e6d10d

Illustration of what happens when we revert a git merge commit

Conflict Resolution When Reverting a Commit

Sometimes, conflicts may arise when reverting a commit, particularly if the commit being reverted conflicts with later changes in the codebase. In such cases:

  1. Git will pause the revert: We need to manually resolve conflicts. Git will mark the conflicting files and require intervention.
  2. Resolve the conflicts: We open each conflicting file, resolve the conflicts marked by Git, and save the changes.
  3. Stage the resolved files: git add <file-path>
  4. Continue the revert: git revert --continue

Conclusion

Using git revert to undo merge commits ensures that every change and correction is documented within the commit history.

Additionally, understanding the appropriate scenarios to apply git reset versus git revert enables us to make better decisions, especially when considering collaborative workflows or local-only changes.

You can read more about this subject in the FAQs section below. If you want to learn more about Git, I recommend these resources:

Source:
https://www.datacamp.com/tutorial/git-revert-merge