Git revert vs reset: Safely Undoing a Pushed Merge Commit
Quick answer
For a merge commit that's already been pushed and potentially pulled by others, git revert is almost always the correct choice over git reset — reset rewrites...
For a merge commit that's already been pushed and potentially pulled by others, git revert is almost always the correct choice over git reset — reset rewrites history (requiring a disruptive force-push and reconciliation from every collaborator), while revert adds a new commit that undoes the changes, preserving history and working safely with anyone who's already pulled the original commit.
The Problem
A merge that was pushed to a shared branch turns out to be wrong — merged too early, contains a bug, or simply shouldn't have happened yet — and needs to be undone in a way that's safe for everyone else who might have already pulled it.
Why revert Is the Correct Choice Here
git reset moves your branch pointer backward, effectively removing commits from the branch's history — this requires a force-push to update the remote (since the remote's history no longer matches), and anyone who already pulled the original commits now has local history that diverges from the rewritten remote, requiring them to manually reconcile their own repository. git revert, in contrast, doesn't remove or rewrite any existing history at all — it adds a brand new commit that applies the inverse of the original changes, achieving the same end result in your codebase (the change is effectively undone) while every existing commit remains exactly as it was, requiring only a normal push, with zero special coordination needed from anyone else.
The Fix
Identify the merge commit you want to undo:
git log --oneline --merges
Revert the merge commit, specifying which parent represents the "mainline" you want to preserve (this is required specifically for merge commits, since they have multiple parents, and Git needs to know which side represents the branch you're reverting on):
git revert -m 1 <merge-commit-hash>
-m 1 tells Git the first parent (typically the branch you merged into, like main) is the mainline to preserve, reverting the changes that were introduced by the second parent (the branch that was merged in) — getting this parent number wrong reverts the opposite of what you actually intend, so double-check which parent is which if you're at all unsure, using git show <merge-commit-hash> to inspect the merge commit's actual parents beforehand.
Push the revert commit normally, no force-push needed, since you've added a new commit rather than rewritten any existing history:
git push origin main
Be aware of a specific complication with reverting merges: if you later want to re-merge the same branch again (after fixing whatever issue caused the original revert), Git may not automatically recognize that the previously reverted changes should be reapplied, since the revert commit itself now exists in history as if those changes were deliberately undone. When you're ready to re-merge, you may need to also revert the revert commit first, or use a specific merge strategy that accounts for this history — this is a known, documented complexity of reverting merge commits specifically (as opposed to reverting simple, single-parent commits), worth being aware of if you expect to reintroduce the same branch's changes later.
Still Not Working?
If you genuinely do need to use reset despite the commit being pushed — for example, on a branch you've confirmed no one else has pulled from yet, where a clean rewritten history is preferable to an added revert commit — coordinate explicitly with your team before force-pushing, and ensure everyone understands they'll need to reconcile their local repositories afterward:
git reset --hard <commit-before-the-merge>
git push --force-with-lease origin main
This should be the exception rather than the default approach for anything already shared with others — reach for revert as the default, safe choice for undoing pushed changes, and only use reset-plus-force-push when you have specific, confirmed knowledge that doing so won't disrupt anyone else's already-pulled history.