Aborting and recovering a rebase gone wrong Jump to heading

Rebases go wrong in two phases. During the rebase, you hit the fifth conflict in a row, realise you rebased onto the wrong branch, or resolve a conflict badly and continue. After the rebase, you discover that a commit disappeared, a resolution dropped someone’s change, or the branch now contains commits that belong elsewhere. Both phases are recoverable, because rebase never destroys the original commits — it creates new ones and moves the branch name. The old commits remain reachable through ORIG_HEAD and the reflog. This page gives the exits during a rebase and the recovery after one, as part of interactive rebase workflows.

When to use this approach Jump to heading

  • A rebase in progress has become confusing and you want out.
  • A conflict was resolved wrongly and you have already continued past it.
  • A completed rebase lost commits or changes.
  • You rebased onto the wrong base, or with the wrong range — for ranges, see rebasing onto a new base with --onto.

Step 1 — Know the three exits during a rebase Jump to heading

While a rebase is stopped, three commands end or alter it, and they are not interchangeable.

abort, quit and skipabort returns the branch and working tree to exactly where they were before the rebase started. quit stops the rebase and leaves HEAD wherever it is, with the commits applied so far, without touching the branch name. skip drops the current commit and continues with the next.What happensUse when--abortback to before the rebasethe whole rebase was a mistake--quitstop here, keep progresswant to salvage partial work--skipdrop this commit, go oncommit doesn't belong--abort is the safe default when you are unsure abort, quit and skipabort returns the branch and working tree to exactly where they were before the rebase started. quit stops the rebase and leaves HEAD wherever it is, with the commits applied so far, without touching the branch name. skip drops the current commit and continues with the next.What happensUse when--abortback to before the rebasethe whole rebase was a mistake--quitstop here, keep progresswant to salvage partial work--skipdrop this commit, go oncommit doesn't belong--abort is the safe default when you are unsure
git status                    # confirms a rebase is in progress and which commit stopped
git rebase --abort            # restore the branch exactly as it was

--abort discards all conflict resolutions made during this rebase. If you invested real effort, --quit keeps the commits applied so far reachable from HEAD, so you can inspect them before deciding.

git rebase --quit
git log --oneline -5          # the partially rebased commits, on a detached HEAD
git branch salvage/rebase-partial HEAD

Step 2 — Redo a single bad resolution during the rebase Jump to heading

If you resolved a conflict, continued, and realise a few commits later that the resolution was wrong, you do not need to abort everything. The bad resolution is in a specific commit; let the rebase finish, then fix that commit with a fixup — or, if it is the current commit, amend it.

# The bad resolution is in the commit just applied — fix it now
git show HEAD -- src/conflicted/file.py
$EDITOR src/conflicted/file.py
git add src/conflicted/file.py && git commit --amend --no-edit
git rebase --continue

If the conflicted file is a mess and you want the conflict back as it was, git checkout --conflict=zdiff3 -- <path> regenerates the conflict markers for the commit currently being applied.

Step 3 — Undo a completed rebase with ORIG_HEAD Jump to heading

When a rebase finishes, Git sets ORIG_HEAD to the branch tip before the rebase. Immediately after, resetting to it undoes the whole rebase.

git log --oneline -3 ORIG_HEAD      # the pre-rebase tip
git reset --hard ORIG_HEAD

⚠️ SAFETY WARNING: git reset --hard discards uncommitted changes in the working tree. Commit or stash anything you want to keep first. ORIG_HEAD is also overwritten by the next reset, merge or rebase, so use it only immediately after the rebase; otherwise use the reflog as in Step 4.

The old commits survive a rebaseBefore the rebase the branch pointed to C3. The rebase created C1', C2' and C3' on the new base and moved the branch name to C3'. The original commits are still in the repository, reachable through ORIG_HEAD and the branch's reflog.rebase moves the name, it does not delete commitsnew baseM1M2after rebaseM2C1'C2' C3'ORIG_HEADbaseC1C2C3git reset --hard ORIG_HEAD puts the branch name back on C3 The old commits survive a rebaseBefore the rebase the branch pointed to C3. The rebase created C1', C2' and C3' on the new base and moved the branch name to C3'. The original commits are still in the repository, reachable through ORIG_HEAD and the branch's reflog.rebase moves the name, it does not delete commitsnew baseM1M2after rebaseM2C1'C2' C3'ORIG_HEADbaseC1C2C3git reset --hard ORIG_HEAD puts the branch name back on C3

Step 4 — Recover later using the branch reflog Jump to heading

Days later, ORIG_HEAD is long gone, but the branch’s reflog records every position it has had. The entry just before “rebase (start)” or “rebase (finish)” is the pre-rebase tip.

git reflog show --date=iso feature/pdf | head -12
# 3a9e5d1 feature/pdf@{2026-10-01 16:42}: rebase (finish): refs/heads/feature/pdf onto 5c0f...
# 8b3e4f2 feature/pdf@{2026-10-01 11:05}: commit: Add page numbering
# Compare the old and new versions before choosing what to restore
git range-diff 8b3e4f2...feature/pdf
# Restore entirely, or recover just the lost commit
git branch feature/pdf-before-rebase 8b3e4f2
git cherry-pick <lost-commit-sha>

git range-diff is the best tool for spotting what changed in a rebase: it pairs each old commit with its new version and shows commits that disappeared.

Step 5 — Make future rebases easier to undo Jump to heading

A few settings reduce both the chance of a bad rebase and the cost of one.

git config --global rerere.enabled true        # repeated conflicts are resolved the same way next time
git config --global merge.conflictStyle zdiff3 # see the base in every conflict
git config --global rebase.autoStash true      # stash and restore uncommitted changes automatically
# Before a risky rebase, mark the current tip
git branch backup/feature-pdf-$(date +%H%M)
Choosing the recovery pathIf the rebase is still in progress, abort or quit. If it finished moments ago, reset to ORIG_HEAD. If it finished earlier, find the pre-rebase tip in the branch reflog and compare with range-diff before restoring or cherry-picking what was lost.Where are you relative to the rebase?still in progress--abort / --quitnothing lost yetjust finishedreset ORIG_HEADundo in one stepdays laterbranch reflogrange-diff, then restorein every case the original commits still exist — the work is finding them Choosing the recovery pathIf the rebase is still in progress, abort or quit. If it finished moments ago, reset to ORIG_HEAD. If it finished earlier, find the pre-rebase tip in the branch reflog and compare with range-diff before restoring or cherry-picking what was lost.Where are you relative to the rebase?still in progress--abort / --quitnothing lost yetjust finishedreset ORIG_HEADundo in one stepdays laterbranch reflogrange-diff, then restorein every case the original commits still exist — the work is finding them

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

I pushed the bad rebase already. What now? Jump to heading

Restore the branch locally from the reflog, then push the restored version with --force-with-lease. Anyone who fetched the bad version must reset to the restored one. The steps match recovering from an accidental force-push.

Why does the rebase stop on commits that seem to have no conflict? Jump to heading

It stops on edit instructions, on failed exec commands, and when a commit becomes empty because its changes are already in the new base. For empty commits, --skip is usually right.

Is there any way a rebase can lose work permanently? Jump to heading

Only uncommitted changes discarded by reset --hard, or commits whose reflog entries have expired and been garbage-collected. Committed work is recoverable for weeks by default.