Git Course 0%

Recover from a failed merge or rebase

Advanced Git CLI ≈ 9 min

What you will learn

  • How to get out of a half-finished merge or rebase
  • How to read what Git says about the state you are in
  • How to undo a merge, before and after pushing

After this lesson you can

  • I can always return to the state before I started, which makes conflicts much less frightening

Why this matters

The worst moment in Git is being halfway through something you do not understand, with the shell prompt showing a state you did not ask for. The fix is one command, and knowing it in advance turns a conflict from an emergency into a task.

The escape hatches

You are in Get out with Result
A merge with conflicts git merge --abort Exactly where you were before the merge
A rebase with conflicts git rebase --abort Exactly where you were before the rebase
A cherry-pick git cherry-pick --abort Same
A revert that conflicted git revert --abort Same

All four are safe and complete: they restore the branch, the staging area and your files to the state before the operation started. Nothing is lost, because nothing had been committed yet.

Where am I?

git status always says, in its first two lines. During a merge:

Output
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   docs/faq.md

During a rebase:

Output
interactive rebase in progress; onto c9c26d7
Last command done (1 command done):
   pick 9e420d2 docs: clarify the licence answer
No commands remaining.
You are currently rebasing branch 'docs/licence-wording' on 'c9c26d7'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Both messages contain the commands you need. Git is not being cryptic here; it is telling you the three options, and one of them is always "go back to how it was".

Aborting a merge

Terminal
$ git merge docs/licence-wording
Auto-merging docs/faq.md
CONFLICT (content): Merge conflict in docs/faq.md
Automatic merge failed; fix conflicts and then commit the result.
Terminal
$ git merge --abort
$ git status --short
$ git log --oneline -1
c9c26d7 docs: shorten the licence answer

Clean tree, same commit, as though the merge never happened. Aborting is a perfectly respectable choice: it buys you time to ask the other author what they meant before resolving (Section 11).

Rebase: continue, skip or abort

A rebase replays your commits one at a time, so it stops at each one that conflicts:

Output
CONFLICT (content): Merge conflict in docs/faq.md
error: could not apply 9e420d2... docs: clarify the licence answer
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Option Use when
git rebase --continue You resolved the conflict and staged the files. Git commits and moves to the next one
git rebase --skip This commit's change is genuinely no longer needed, usually because the same fix is already on the new base
git rebase --abort You want to stop and think. Nothing is lost

--skip is the one to be careful with: it drops that commit entirely. Use it only when you have looked at the change and confirmed it is already present.

Terminal
$ git rebase --abort
$ git log --oneline -2
9e420d2 docs: clarify the licence answer
d3b92ec chore: add CI configuration and contributing guide

Back to the original branch, with the original commits and their original hashes.

Undoing a merge that is already committed

Once the merge commit exists, the escape hatches no longer apply and the pushed question decides again.

Not pushed: the merge is the last commit, so move the branch back:

Terminal
$ git reset --hard ORIG_HEAD

ORIG_HEAD is set by the merge itself, which is exactly what it is for.

Pushed: revert it. A merge commit has two parents, so Git needs to know which side to keep:

Terminal
$ git revert HEAD
error: commit 85fd3d5f2a165b6f0e3bc4f9c9fb7c18a7ef5174 is a merge but no -m option was given.
fatal: revert failed
Terminal
$ git revert -m 1 HEAD
[main 0abc660] Revert "Merge branch 'docs/licence-wording'"
 1 file changed, 1 insertion(+), 1 deletion(-)

-m 1 means "keep the first parent", which is the branch you merged into, normally main. In other words, undo the incoming changes and keep the branch as it was.

How to do it

Four commands cover the whole lesson:

Terminal
$ git merge --abort
$ git rebase --abort
$ git reset --hard ORIG_HEAD     # merge already committed, not pushed
$ git revert -m 1 <merge hash>   # merge already pushed

When in doubt, run git status and read its parenthetical hints; they name the right command for the state you are in.

Common mistakes

  • Continuing a rebase without staging the resolved files, which Git refuses with a message about unmerged paths.
  • Using --skip to make a conflict go away, which silently drops that commit's change.
  • Forgetting -m 1 when reverting a merge, then not reading the error, which says exactly what is missing.
  • Panicking and deleting the repository folder. The escape hatches always work, and a clone is not a backup of your unpushed work.
  • Resolving the same conflict repeatedly in a long rebase instead of aborting and merging.

Try it yourself

Goal: create a conflict, escape it twice, then undo a completed merge.

  1. On two branches, change the same line of docs/faq.md differently and commit both.
  2. Merge one into the other, see the conflict, then run git merge --abort and confirm the tree is clean.
  3. Try again with git rebase instead, read the status message in full, and run git rebase --abort.
  4. Now complete the merge: resolve the conflict, git add, git commit.
  5. Undo it with git reset --hard ORIG_HEAD, and confirm the merge commit is gone.

Expected result: two clean escapes and one completed merge undone, with the branch back at the commit it started from each time.

Show solution

Step 3's status output is the one to read carefully: it names the branch, the commit it is replaying, and all three options. Every mid-operation state in Git announces itself the same way, so getting used to reading it is worth more than memorising any single command.

Check yourself

1. A merge stopped with conflicts and you want to think about it tomorrow. What do you run?
2. During a rebase, what does git rebase --skip do?
3. Why does reverting a merge commit need -m 1?

Key terms

Merge conflict Rebase Merge Revert