A Complete Guide to Safely Reverting a Merge Commit with git revert -m and Re-merging Accurately

Git tutorial - IT technology blog
Git tutorial - IT technology blog

It’s 2 AM, and PagerDuty is sounding alarms relentlessly. Alerts report that the payment gateway is returning massive HTTP 500 errors. The culprit: a pull request merged into the main branch just 5 minutes ago triggered the CI/CD pipeline to auto-deploy to the cluster.

Still groggy, your first instinct is to open the terminal and immediately run git revert <commit_hash>. But Git refuses to execute it:

error: commit 9a4f21b is a merge but no -m option was given.
fatal: revert failed

Production is down, and every minute of downtime costs thousands of dollars. Here is how to resolve the incident in 30 seconds without messing up your team’s git tree.

Emergency Rollback in 3 Steps

If the server is down and you need to restore code to a safe state immediately, follow this process:

Step 1: Get the Hash of the Recently Deployed Merge Commit

Check the last 5 commits on the main branch:

git log --oneline -n 5

The terminal will return a log like this:

9a4f21b (HEAD -> main) Merge pull request #42 from feature/payment-v2
8c1e34a feat: update checkout form
5d2b10f fix: handle payment gateway timeout
1a2b3c4 chore: update dependencies

Step 2: Run the Revert Command with the -m 1 Flag

Specify the mainline branch as the reference point for the rollback:

git revert -m 1 9a4f21b

Git will automatically open an editor to confirm the commit message. Simply keep the default message Revert "Merge pull request #42 from feature/payment-v2" and save.

Step 3: Push Directly to the Remote to Trigger a Rollback Build

git push origin main

The CI/CD pipeline will immediately rebuild the clean codebase from before the merge. System stability is restored. Now, you can take your time to understand Git’s underlying mechanics.

Understanding the -m Flag and Parent Numbers in Git

A regular commit has only 1 parent commit. When executing git revert <hash>, Git simply compares that commit with its parent to reverse the changes.

A merge commit is different. It is the convergence point of at least two branches, meaning it has 2 or more parent commits:

  • Parent 1 (Mainline): The receiving branch (usually main or production).
  • Parent 2: The branch being merged in (e.g., feature/payment-v2).

To inspect the order of these parents, run:

git show 9a4f21b

Observe the second line in the output:

commit 9a4f21b0e419b48... 
Merge: 1a2b3c4 8c1e34a
Author: Senior Dev <[email protected]>
Date:   Fri Oct 2 02:00:00 2026

What these parameters mean:

  • 1a2b3c4 is Parent 1 (HEAD of main right before the merge).
  • 8c1e34a is Parent 2 (the last commit from the feature/payment-v2 branch).

The -m 1 parameter (short for --mainline 1) specifies the instruction: “Take Parent 1 as the reference baseline and revert all changes introduced by Parent 2.”

The Unexpected Consequence of Reverting a Merge Commit

Many developers mistakenly believe that reverting completely wipes the feature branch from commit history. But that is not how Git works.

The history of past commits remains intact on the Git tree. Git simply creates a new commit that inverts the code at the time of the revert. This creates major trouble when you try to re-merge the feature branch later on.

Re-merging Technique After Fixing the Bug

A very common scenario: The next day, the team identifies the root cause of the Null Pointer error, fixes it, and pushes a new commit to feature/payment-v2. You confidently open a PR targeting main. But when checking the Files Changed tab, you are stunned: All the previous feature code is gone, and the PR only shows the few lines from the new fix commit.

Why does this happen? The main branch still records that the earlier commits were introduced once and subsequently discarded deliberately. Git considers this an intentional removal, so it ignores all the old changes.

3-Step Process to Safely Re-merge:

Step 1: Revert the Previous Revert Commit

We need to restore all original code on main by reversing the previous rollback commit:

# Sync with the latest main branch
git checkout main
git pull origin main

# Get the hash of the revert commit (e.g., a1b2c3d)
git log --oneline -n 3

# Reverse the revert commit (note: this is a regular single commit, so do not use the -m flag)
git revert a1b2c3d

The original feature code is now restored on main.

Step 2: Merge the Bug-Fixed Feature Branch

git merge feature/payment-v2

Git will combine both the restored original code and the latest bugfix commits.

Step 3: Resolve Conflicts (If Any) and Push to Remote

git add .
git commit -m "fix: resolve conflicts and re-merge feature/payment-v2"
git push origin main

Battle-Tested Practices for Handling Git Incidents

After years of running on-call for microservices systems with dozens of daily deploys, here are 4 principles you should follow:

  • Avoid git reset --hard on shared branches: Running git reset --hard HEAD~1 combined with git push --force will disrupt the local workspaces of other developers on the team. Worse, it destroys the entire audit trail in your CI/CD pipeline.
  • Specify incident context in the commit message: When reverting, attach the incident ticket to the message for easy tracing later: git revert -m 1 9a4f21b --no-edit && git commit --amend -m "revert: rollback PR #42 due to checkout timeout (INC-1042)". Note that you should not pass -m "message" directly alongside -m 1, because in a revert command, Git interprets -m as --mainline by default.
  • Create an intermediate branch for re-merging: Instead of re-merging directly into main, create a branch like re-merge/payment-v2 and open a Pull Request. Have teammates review the diff before merging to ensure no logic is missing.
  • Standardize runbooks for your team: Document the git revert -m 1 workflow in your project’s on-call runbook. This allows even freshers or junior engineers on night shift to rollback independently within 2 minutes without waking up the Tech Lead.
Share: