Table of Contents

Introduction

Sometimes a rebase stops on a conflict and you realize you don't want to deal with it right now, or at all. Maybe the conflict is bigger than you expected, or you rebased onto the wrong branch. git rebase --abort gets you out: it cancels the rebase and puts your branch back exactly as it was before you started.

In this article, we'll:

  1. Watch git rebase --abort call off a rebase that stopped on a conflict
  2. See what it throws away and what it keeps
  3. Cover how to undo a rebase you already finished, since --abort can't help with that one

What is git rebase --abort?

git rebase --abort stops a rebase that's in progress and resets HEAD to the branch you were rebasing, at the commit it pointed to before the rebase began. The git rebase documentation puts it as "Abort the rebase operation and reset HEAD to the original branch." Your working directory and staging area are reset to match that commit too, so any conflict you were partway through resolving is gone.

It only works while a rebase is stopped. Once a rebase has finished, there's nothing in progress to abort.

Watch it happen

Our sample repo has a rebase of feature onto main stopped on a conflict in styles.css. Here is how it got there: we ran git rebase main on feature. Git reapplied "Add search box", "Fix typo in search box" and "Add search tests" onto main's "Switch the header to grid" (ada2e79), then stopped on "Space out the header links", because it and main both changed the same line of styles.css. We haven't touched the conflict. Here's git rebase --abort:

  1. Before: feature points at its original tip 791fd8e, above the four original commits. The rebase has created three new commits on top of main at ada2e79, and HEAD is detached on the last one, d392153. Git stopped before creating the new commit for "Space out the header links": REBASE_HEAD points at the original it was replaying, and styles.css is unmerged.
  2. Git abandons the unfinished replay of "Space out the header links", removes REBASE_HEAD and clears the conflict in styles.css.
  3. HEAD moves back to 791fd8e and is attached to feature again. The three new commits, a50dc9c, 13f5b4f and d392153, are now reachable only from the reflog. styles.css goes back to its version in 791fd8e.
  4. feature doesn't move at all, and neither does main. During a rebase, Git only moves the branch at the very end, so feature was sitting on 791fd8e the whole time.

Before and after

Before, git log --all shows the new commits stacked on main with HEAD on them, and the untouched original feature branching off 96c4fc2. After, the new commits are gone from the log and the repository looks just like it did before anyone typed git rebase: feature and main diverging at "Fix header layout". git status goes from ## HEAD (no branch) with UU styles.css (unmerged, both sides changed it) to a clean ## feature. Git prints nothing at all for an abort:

The raw git output, if you want to read along in text

git log --oneline --graph --all

before

* d392153 (HEAD) Add search tests
* 13f5b4f Fix typo in search box
* a50dc9c Add search box
* ada2e79 (main) Switch the header to grid
* 8c02d5b Update dependencies
* a0b2db3 Add user settings page
| * 791fd8e (feature) Space out the header links
| * 1117a34 Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

after

* 791fd8e (HEAD -> feature) Space out the header links
* 1117a34 Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * ada2e79 (main) Switch the header to grid
| * 8c02d5b Update dependencies
| * a0b2db3 Add user settings page
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

Is it safe?

Caution git-sim pre-flight

Calls off the rebase: feature and HEAD go back to 791fd8e, and the staging area and working directory are reset to match.

What you would lose

  • your edits to styles.css since the rebase stopped (not recoverable)

The way back

  • The new commits stay in the reflog for a while: git reflog, then git reset --hard <sha>
  • Run the same rebase again to get the conflict back; the edits themselves can't be recovered.

For your committed work, yes. --abort goes back to commits that already exist, so every original commit on feature is exactly where it was. Two things are thrown away:

  • The new commits made so far, here a50dc9c, 13f5b4f and d392153. They were only ever there for the rebase, and they're easy to make again by running the same rebase.
  • Any conflict work in your files. If you had spent twenty minutes editing styles.css into shape and hadn't committed it, the reset overwrites it. The same goes for any other uncommitted edits made during the rebase.

If you've already resolved some of the conflicts and just want to stop for now, keep in mind that resolutions you finished with git rebase --continue became commits, and those are among the new commits --abort drops. They're still reachable through the reflog for a while if you need to fish one out. If you had rerere turned on, --abort also clears what it had recorded for the conflict you were in the middle of.

When a rebase stops on conflict after conflict in code I don't know well, I usually abort and merge instead. A merge asks me to resolve everything once, against the final state of both branches, rather than once per commit.

How to undo it

An abort itself doesn't need undoing, since it only returns you to where you were. If you change your mind, start the rebase again:

git rebase main

The more common problem is the opposite one: the rebase already finished and you regret it. --abort refuses then ("No rebase in progress?"), so use the branch's reflog instead. It records where feature pointed before the rebase:

git reflog feature
git reset --hard feature@{1}

Right after a rebase, ORIG_HEAD holds the same commit, so git reset --hard ORIG_HEAD works too, as long as nothing since has changed it. git reset --hard discards uncommitted changes, so check git status first.

Useful forms

  • git rebase --abort cancels the rebase and returns the branch to its starting commit.
  • git rebase --quit also ends the rebase but leaves HEAD, the index and your files where they are, detached on the rebased commits. That's handy when you want to keep what the rebase has done so far without finishing it.
  • git merge --abort and git cherry-pick --abort do the same job for a stopped merge and a stopped cherry-pick.

Try it on your repository

pip install git-sim
git-sim rebase --abort

git-sim runs the abort in a copy of your repository, so yours isn't touched, and shows where your branch goes back to and which new commits would be dropped.

Common questions

How do I cancel a rebase in progress?

Run git rebase --abort. It ends the rebase and resets your branch, staging area and working directory to where they were before the rebase started.

Does git rebase --abort lose my commits?

No. Your original commits are untouched, and the branch goes back to them. It drops only the new commits the rebase had made so far and any uncommitted conflict resolution.

What is the difference between git rebase --abort and --quit?

--abort resets HEAD to the original branch. --quit stops tracking the rebase but leaves HEAD detached where it is, with your files unchanged.

Can I use git rebase --abort after the rebase has finished?

No. There's no rebase in progress to abort. Use git reflog to find the branch's old tip and git reset --hard to it.

Summary

In this article, we watched git rebase --abort send HEAD back to feature at 791fd8e and drop the three new commits the rebase had made, and covered what an abort throws away and how to reset a rebase you already finished.

Next steps

git rebase --continue is the way through the conflict instead of back out. git reflog shows how to find a branch's old tip, which is handy to know before you rebase anything important.