Defining "bad merge"
A bad merge can mean: you merged the wrong branch, you resolved conflicts incorrectly, the merge introduced a regression, or you merged before review was complete. Each has a different fix. The key is acting fast and using the right tool.
Case 1: not yet pushed
If the merge is local-only, undo it cleanly:
git reset --hard ORIG_HEAD
ORIG_HEAD records the pre-merge HEAD; this command rewinds the branch to before the merge. Add HEAD@{1} if ORIG_HEAD has been overwritten.
Case 2: pushed, others have not pulled
If you can confirm no one pulled, force-push the rewind:
git reset --hard ORIG_HEAD
git push --force-with-lease
Coordinate via chat first. Force-push on shared branches is a teamwork activity.
Case 3: pushed, others have pulled
Now history rewriting is dangerous. Use revert instead:
git revert -m 1 <merge-sha>
-m 1 tells revert to undo the merge by reapplying main's pre-merge state, treating parent 1 as the canonical line. The result is a new commit that undoes the merge's effect.
Re-merging after a revert
The next gotcha: if you simply re-merge the original branch, Git considers it already merged and does nothing. To re-merge, first revert the revert:
git revert <revert-sha>
# or rebase the feature branch and merge again
git checkout feature/login
git rebase main
git checkout main
git merge feature/login
Case 4: bad conflict resolution
If the merge mechanics were correct but conflict resolution introduced bugs, fix forward with a regular commit:
git checkout main
# ...edit the affected files...
git commit -m "Fix conflict resolution from merge of feature/login"
Mark the original merge in the commit message for traceability.
Case 5: merged the wrong branch
Local-only:
git reset --hard ORIG_HEAD
git merge correct-branch
Already pushed: revert as in Case 3, then merge the correct branch.
Inspecting a merge
git log -1 --format=fuller --stat HEAD
git show -m HEAD # show as separate diffs against each parent
git diff HEAD^1 HEAD # what the merge added vs main side
git diff HEAD^2 HEAD # what the merge added vs feature side
Avoiding bad merges
- Always use
--no-ffon long-lived branches;--ff-onlyon short ones. - Configure CI to run on the merge result, not just the branch tip.
- Use
git mergetoolfor tricky conflicts; eyeballing is error-prone. - Run tests immediately after every merge.
The recovery toolkit
ORIG_HEAD- automatically set before merges, resets, rebases.git reflog- records every HEAD movement.git revert -m- undo a merge by creating a new commit.git push --force-with-lease- safer force push.
Bad merges feel catastrophic in the moment. They are not. Pause, identify which case applies, pick the right tool, and recover.