Recovery

Recovering from a broken interactive rebase

Common errors during interactive rebase (wrong actions, conflicts, editor issues) and how to recover, including --abort, --edit-todo, and reflog-based recovery.

Who This Is For
  • Anyone actively handling a Git mistake
  • Readers who want a conservative rescue habit before trouble happens
Prerequisites
  • Stop mutating the repo further
  • Be ready to inspect `git reflog`, `git status`, and `git log --graph`
Common Risks
  • Running more reset or rebase commands before preserving a checkpoint
  • Changing shared history before assessing blast radius

Citations & Further Reading

  1. Git rebase [Official]
  2. Git Tools Rewriting History [Book]

What you will learn

  • Understand the core purpose of Recovering from a broken interactive rebase
  • Master the basic usage and common options of Recovering from a broken interactive rebase
  • Common errors during interactive rebase (wrong actions, conflicts, editor issues) and how to recover, including --abort, --edit-todo, and reflog-based recovery.
  • Understand key concepts: What interactive rebase does
  • Know when to use this feature and when to avoid it

Start with a problem

You just ran a Git command and the result wasn't what you expected — maybe you even lost some commits. This has happened before, and you want a reliable set of recovery techniques.

The short version

Interactive Rebase Commit RearrangementInteractive rebase lets you reorganize, modify, squash, or drop commits during replay. When things go wrong, Git provides --abort, --edit-todo, and reflog recovery.
Before rebase (original chain)
main
ABCD
feature
BEF
After rebase (rearranged chain)
main
ABCD
feature
DE'F'

Interactive rebase (git rebase -i) lets you reorder, modify, squash, or drop commits while replaying them. When things go wrong, Git provides --abort, --edit-todo, and reflog as layered recovery mechanisms.

What interactive rebase does

Before rebase:
A --- B --- C --- D --- E (feature)
       \
        X --- Y (main)

After rebase:
A --- B --- C --- D --- E (feature, old, to be discarded)
       \
        X --- Y --- B' --- C' --- D' --- E' (feature, new)

Interactive rebase opens an editor listing the commits to replay, each with an action prefix:

pick B    apply commit B
pick C    apply commit C
pick D    apply commit D
pick E    apply commit E

# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like squash, but discard this commit's log message
# d, drop <commit> = remove commit

Scenario 1: Conflict during rebase

Like a normal rebase or cherry-pick, conflicts can occur when replaying a commit.

$ git rebase -i HEAD~4
# After saving the editor...

$ git rebase main
Auto-merging src/auth.js
CONFLICT (content): Merge conflict in src/auth.js
error: could not apply abc1234... feat: update auth logic
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 with "git rebase --skip".
hint: To abort and get back to the original branch before "git rebase",
hint: run "git rebase --abort".

$ git status
interactive rebase in progress; onto def5678
Last command done (1 command done):
   pick abc1234 feat: update auth logic
Next commands to do (3 remaining commands):
   pick bcd2345 fix: correct edge case
   squash cde3456 feat: add error handling
  (use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'feature' on 'def5678'.
  (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)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   src/auth.js

Your four options:

Option A: Resolve conflicts and continue

# 1. Edit conflicted files
vim src/auth.js

# 2. Mark as resolved
git add src/auth.js

# 3. Continue
git rebase --continue
# Git may open an editor for the commit message (for edit/reword actions)

Option B: Skip the current commit

# Don't apply this conflicting commit, move on to the next
git rebase --skip

Option C: Abort entirely

# Go back to the pre-rebase state
git rebase --abort

Option D: Modify the rebase plan

# Open the editor to modify the remaining rebase plan
git rebase --edit-todo
# For example, change a pick to drop or squash
# Save and continue
git rebase --continue

Scenario 2: Wrong action in the rebase editor

Accidentally wrote drop instead of pick

# You meant to pick this commit but typed drop by mistake
drop abc1234 feat: important new feature  ← this commit gets discarded!

Recovery:

# Method 1: If rebase is still in progress
git rebase --abort

# Method 2: If rebase already finished, use reflog
git reflog
# Find the pre-rebase state
# git reset --hard feature@{1}  or
# git reset --hard <pre-rebase-SHA>

Lost commit info after squash

# Squash combines commit messages, but you might accidentally delete important descriptions
pick abc1234 feat: base framework
squash bcd2345 fix: correct issue

After squash, the editor opens for the combined message. If you saved an incomplete message:

# Amend the most recent commit message
git commit --amend

# If rebase is already complete
git rebase -i HEAD~1  # use reword to fix

Stuck after an edit action

# You chose edit for a commit, rebase stopped:
$ git status
interactive rebase in progress; onto def5678
Last command done (1 command done):
   edit abc1234 feat: update auth logic
  (use "git commit --amend" to amend the commit)
  (use "git rebase --continue" to continue)
# 1. Make your changes
vim src/auth.js
git add src/auth.js

# 2. Amend the commit message (optional)
git commit --amend

# 3. Continue rebase
git rebase --continue

Scenario 3: Editor problems

Don't know how to use the editor

Interactive rebase uses your default editor. If you're unfamiliar with Vim:

# Temporarily use a different editor
GIT_SEQUENCE_EDITOR="code --wait" git rebase -i HEAD~4

# Or set a global default editor
git config --global core.editor "code --wait"  # VS Code
git config --global core.editor "nano"          # nano
git config --global core.editor "vim"           # vim

Rebase errors after saving the editor

$ git rebase -i HEAD~4
error: invalid line 3: blahblah blahblah
Could not execute editor

This usually means the rebase todo file has a syntax error. Git tells you which line is wrong.

# Fix it
git rebase --edit-todo
# Correct the bad line (ensure action is pick/reword/edit/squash/fixup/drop)
git rebase --continue

Scenario 4: Rebase completed but result is wrong

Rebase finished cleanly, but the outcome isn't what you wanted.

Use reflog to recover the pre-rebase state

# Check the reflog
$ git reflog
a1b2c3d (HEAD -> feature) HEAD@{0}: rebase (finish): returning to refs/heads/feature
a1b2c3d HEAD@{1}: rebase (pick): feat: add error handling
b2c3d4e HEAD@{2}: rebase (pick): fix: correct edge case
c3d4e5f HEAD@{3}: rebase (pick): feat: update auth logic
d4e5f6a HEAD@{4}: rebase (start): checkout main
e5f6a7b HEAD@{5}: checkout: moving from main to feature  ← pre-rebase position!
e5f6a7b (feature@{1}) feat: last commit (before rebase)

# Return to pre-rebase state
git reset --hard e5f6a7b
# or
git reset --hard feature@{1}

Partial recovery

If only a specific commit is wrong, find its old SHA in the reflog and cherry-pick the correct version:

# Find the old commit SHA in reflog
git reflog --all | grep "important commit message"

# Cherry-pick the old version
git cherry-pick <old-sha>

Scenario 5: Rebased onto the wrong branch

# Accidentally ran
git rebase -i main   # meant to rebase onto develop

# Recovery
git rebase --abort   # if still in progress

# If already finished
git reset --hard feature@{1}  # back to before rebase
git rebase -i develop          # rebase onto the correct branch

Interactive rebase command quick reference

CommandPurpose
git rebase --continueContinue after resolving conflicts or editing
git rebase --abortCancel entirely, return to pre-rebase state
git rebase --skipSkip the current commit
git rebase --edit-todoEdit the remaining rebase plan
git rebase --quitStop rebase but keep current progress (don't return to pre-rebase)

Difference between --quit and --abort:

  • --abort: fully returns to the pre-rebase state
  • --quit: stops rebase but keeps already-replayed commits on the current branch

Preventive measures

1. Create a backup branch before rebasing

# The most important preventive step!
git branch backup/feature-before-rebase

If the rebase goes wrong, you can always:

git reset --hard backup/feature-before-rebase

2. Preview commits before rebasing

# See what commits will be rebased
git log --oneline main..feature
# Confirm the list of commits to rebase

3. Experiment on a copy

# Create a copy branch
git checkout -b feature/rebase-trial
# Experiment with rebase on the copy
git rebase -i HEAD~4
# Once satisfied, delete original and rename the copy
git branch -D feature
git branch -m feature

4. Automate with GIT_SEQUENCE_EDITOR

If you know what operations you need, use a script instead of manual editing:

# Squash the 3rd commit
GIT_SEQUENCE_EDITOR="sed -i '3s/pick/squash/'" git rebase -i HEAD~4

# Drop all commits containing "WIP"
GIT_SEQUENCE_EDITOR="sed -i '/WIP/s/pick/drop/'" git rebase -i HEAD~10

Quick decision flowchart

Rebase went wrong?
      │
  ┌───┴───┐
  Still in progress?   Already finished?
  │            │
  ↓            ↓
  Conflict?   Recover via reflog
  │            │
  ├─ Resolve → --continue   git reflog
  ├─ Skip → --skip          git reset --hard <old-sha>
  └─ Give up → --abort

Try it yourself

  1. Practice the fix-broken-interactive-rebase command in a test repository and observe state changes before and after
  2. Experiment with different options and compare the output differences
  3. Simulate a real scenario where you would need to use this, and walk through the full process

Further reading

Keep going on the same topic: