Merges feel scarier to undo than normal commits because they have two parents and ten times the ways to go wrong. They're actually fine — once you know which of three situations you're in.
Situation 1: you're still staring at the conflict
The merge never finished. You're mid-conflict and want out:
git merge --abort
Done. Your tree goes back to exactly how it was before you typed git merge. This is the easiest exit in git and the one people forget exists while panicking over conflict markers.
Situation 2: the merge is committed, but not pushed
You finished the merge locally and immediately regretted it. Because nobody else has it, you can safely erase it:
git reset --hard ORIG_HEAD
ORIG_HEAD is git's automatic bookmark of where your branch pointed before the merge started. (This only works until another operation overwrites it — so decide quickly, or find the pre-merge SHA in git reflog instead.)
Situation 3: the merge is pushed
Other people may have pulled it, so rewriting is off the table. You need a revert — but a plain git revert <sha> fails on merge commits, because git can't tell which side of the merge you want to keep. You have to say it:
git revert -m 1 <merge-sha>
git push
The -m 1 means "parent number one is the main line" — that's the branch you merged into (e.g. main). Git keeps that side and inverts everything the other branch brought in. If you ever need the opposite, -m 2 exists, but you almost certainly want 1.
The trap that gets everyone later
You reverted the merge. A week goes by. The feature branch is fixed, you merge it again — and git brings over nothing, or a confusing fraction of the changes.
Why: the original merge commit is still in the branch's history, so git believes those changes were "already merged" — and your revert cancelled them. Re-merging replays history git thinks is done.
The fix is as weird as it sounds: revert the revert.
git revert <sha-of-the-revert-commit>
git merge feature-branch
Now the branch's changes can come in again. It works, it feels ridiculous, and everyone who does it the first time is sure they've broken something.
Roll the branch back with Time Travel
Point at the commit right before the merge. git.tools opens a pull request that puts the branch back in exactly that state — reviewed by your team, no force push, no guessing which parent was which.
Open Time Travel →A note on "just force push it"
Yes, reset --hard to before the merge plus git push --force also undoes a pushed merge. It also silently rewrites history out from under anyone who pulled in between — and if a teammate based work on the merged state, you've turned your mistake into theirs. On a shared branch, a revert (or a restore PR) is the adult option. Save the force push for branches only you touch.