You ran git revert abc1234 to undo a bad merge and Git stopped with:
error: commit abc1234 is a merge but no -m option was given
fatal: revert failed
Fastest fix: for a normal PR merge of a feature branch into main, run git revert -m 1 abc1234. The -m 1 keeps main as the baseline and undoes everything the feature branch added.
The reason for the error: a merge commit has two parents — parent 1 is the branch the merge landed on (usually main), parent 2 is the branch that was merged in. To compute what to undo, git revert needs a single baseline to diff against, so it refuses to guess. Per the official git-revert docs, -m “specifies the parent number (starting from 1) of the mainline.” Pass the wrong number and the revert either does nothing visible or reverts the opposite direction. There is also a second trap most people hit a week later: re-merging the same branch after a revert silently brings back nothing. Both are covered below.
Which bucket are you in?
| Symptom | Likely cause | Jump to |
|---|---|---|
commit ... is a merge but no -m option was given | True merge commit, missing -m | Fix step 1-3 |
Revert ran, but git diff shows changes going the wrong way | -m 2 used where -m 1 was meant | Step 2 |
-m 1 errored on a “squash and merge” PR | Squash is a single-parent commit, no -m needed | Squash vs true merge |
| Re-merged the same branch, nothing came back | The “revert the revert” trap | Step 4 |
-m 1 only undid part of the merge | Octopus merge with 3+ parents | Step 5 |
| GitHub: “this pull request couldn’t be reverted automatically” | Conflict or already-reverted PR | FAQ |
Common causes
Ordered by hit rate, highest first.
1. Running git revert on a merge commit without -m
git revert computes the diff between a commit and its parent, then applies the inverse. A merge commit has two parents, so “its parent” is ambiguous and Git refuses to proceed without -m.
How to spot it: the error string itself — commit ... is a merge but no -m option was given.
2. Using -m 2 when you meant -m 1 (or vice versa)
-m 1 treats parent 1 (the branch the merge landed on, usually main) as the mainline and undoes what came in from the feature branch. -m 2 treats parent 2 (the feature branch) as the mainline and reverts in the opposite direction — almost never what you want when undoing a PR merge.
How to spot it: after the revert, git diff HEAD~1 HEAD shows the diff going the wrong way (it re-adds feature code or removes mainline code).
3. Reverting a squash-and-merge vs. a true merge commit
GitHub’s “Squash and merge” produces a single regular commit with one parent, so git revert <sha> works without -m. Passing -m 1 on a single-parent commit fails with error: mainline was specified but commit <sha> is not a merge.
How to spot it: git show -s --format="%P" <sha> | wc -w — 2 means a true merge commit, 1 means a squash or ordinary commit.
4. Re-merging the same branch after reverting the merge
After reverting a merge, fixing the bug, and re-merging the same branch, the re-merge brings in nothing. The git docs are explicit: “Reverting a merge commit declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in tree changes introduced by commits that are not ancestors of the previously reverted merge.” Git still sees the original feature commits as already merged, so it has no net change to apply.
How to spot it: after re-merging, git diff HEAD~1 HEAD is empty or git log main --oneline -- path/to/feature-file is missing the expected commits.
5. Octopus merge commit with 3+ parents
Automated merge trains and git merge branch-a branch-b branch-c produce octopus merges with three or more parents. git revert -m 1 reverts relative to parent 1 only; the mainline you actually want may be a different parent index.
How to spot it: git show -s --format="%P" <sha> returns three or more SHAs.
Shortest path to fix
Step 1: Confirm it’s a merge commit and read the parents
git show -s --format="%H %P %s" abc1234
# abc1234 def5678 ghi9012 Merge pull request #42 from feature/payment
# ^commit ^parent1 ^parent2
# parent1 (def5678) = main at merge time
# parent2 (ghi9012) = tip of feature/payment
Two parent SHAs confirm a true merge commit. To attach branch names to each parent:
git log --oneline --decorate abc1234^1 -1 # parent 1 (mainline)
git log --oneline --decorate abc1234^2 -1 # parent 2 (merged-in branch)
Step 2: Revert with the correct parent
First, tag a safety point so you can get back instantly:
git tag backup/before-revert HEAD
For a standard PR merge where feature landed on main, keep parent 1 as the baseline:
git revert -m 1 abc1234
This creates one inverse commit that undoes everything the feature branch introduced, leaving main’s prior history untouched. Add --no-edit to accept the default Revert "..." message, or -n (--no-commit) to stage the inverse without committing so you can review it first. If conflicts appear, resolve them and run git revert --continue; to bail out, git revert --abort.
Step 3: Confirm it’s fixed
git log --oneline -5 # a new "Revert ..." commit at the top
git diff HEAD~1 HEAD # the inverse of the original merge diff
git show HEAD --stat # the exact files the revert touched
The reverted code should be gone from your working tree. If git diff HEAD~1 HEAD is empty, the revert applied no change — re-check the -m number or whether this was a squash commit.
Step 4: Re-merge later without losing changes
When the feature is fixed and ready again, you cannot just git merge — the revert told Git you never want those tree changes. You must first revert the revert:
# Find the revert-of-merge commit
git log --oneline | grep "Revert"
# Revert that revert commit (restores the original feature changes)
git revert <revert-of-merge-sha>
# Then merge the fixed branch (any commits added since are picked up here)
git merge --no-ff feature/payment-fixed
Skipping the “revert the revert” step is the single most common reason a re-merge appears empty.
Step 5: Octopus merge with 3+ parents
# List every parent in order
git cat-file -p abc1234 | grep "^parent"
# parent <sha-of-main>
# parent <sha-of-branch-a>
# parent <sha-of-branch-b>
# Revert relative to parent 1 (main); use 2 or 3 to target a different mainline
git revert -m 1 abc1234
One git revert -m N only reverses the change relative to parent N. If the octopus brought in multiple branches you need gone, revert with the correct mainline and inspect git show HEAD --stat to confirm all intended files are covered.
Squash-and-merge vs. a true merge commit
If git show -s --format="%P" <sha> | wc -w returns 1, the PR was squash-merged into a single-parent commit. Drop the -m flag entirely:
git revert <squash-sha> # no -m needed
Squash commits also avoid the re-merge trap, because there is no merge commit in history to confuse later merges.
Prevention
- Use
--no-ffwhen merging feature branches so every merge produces a revertible merge commit (parent 1 = the target branch), not a fast-forward. - Prefer Squash and merge for small PRs: one squash commit reverts cleanly without
-mand sidesteps the re-merge trap entirely. - Document the convention in
CONTRIBUTING.md: “Reverting a PR merge:git revert -m 1 <sha>. Re-merging later: revert the revert first.” - For temporary removals, prefer a feature flag over reverting — reverts in long-lived branches create confusing history and complicate re-merges.
- Test the revert in a throwaway branch first:
git switch -c sandbox/test-revert && git revert -m 1 abc1234, verify, then apply tomain. - List merge commits quickly with
git log --merges --oneline -10when you need to target one.
FAQ
Q: Why does -m 1 mean “keep main” and -m 2 mean “keep the feature branch”?
A: When you run git merge feature on main, the merge commit’s parent 1 is the commit main pointed at when you merged, and parent 2 is the tip of feature. git revert -m 1 rewinds the tree to look like parent 1 — i.e., main before the merge.
Q: I re-merged the same branch after a revert and got an empty merge. Why?
A: Reverting the merge declared you never want those tree changes, so Git treats the original feature commits as already applied-and-reverted and brings in nothing. Revert the revert commit first, then merge again. Any commits added to the branch since the first merge will come in on that final git merge.
Q: Can I revert just a few commits from the merged branch instead of the whole merge?
A: Yes. List the branch’s commits with git log --oneline abc1234^1..abc1234, then git revert <commit-sha> for each one you want gone. This avoids the whole-merge re-merge trap because you never reverted the merge commit itself.
Q: git revert -m 1 vs. git reset --hard <pre-merge-sha> — which should I use?
A: If the merge is already pushed to a shared branch, use git revert — it adds a new commit and never rewrites public history. git reset --hard rewrites history and needs a force-push, which disrupts everyone who already pulled. Reserve reset --hard for merges that are still local and unpushed.
Q: GitHub says “this pull request couldn’t be reverted automatically.” What now?
A: GitHub’s PR Revert button runs the equivalent of git revert -m 1 and opens a new revert PR. It fails with that message when the code changed since the merge (conflicts) or the PR was already reverted. Fall back to reverting locally: git revert -m 1 <merge-sha>, resolve any conflicts, then push a branch and open the PR yourself.
Q: Does reverting a merge delete the feature branch?
A: No. The branch and all its commits stay in the object store. The revert only adds one commit to main that undoes the net change — it never touches the feature branch or its history.