C.W.K.
Stream
Lesson 03 of 04 · published

Recover From a Bad Pull or Rebase

~24 min · playbook, reflog, rebase

Level 0Untracked Rookie
0 XP0/47 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Recover from a bad pull, rebase, or reset

Sooner or later you will run a Git command, watch a wave of red text scroll by, and feel your stomach drop. The good news: almost every "I just lost my work" Git situation is recoverable. The recovery procedure is the same shape every time: stop typing destructive commands, find the lost tip with git reflog, anchor it to a branch, evaluate, then choose how to integrate.

The first move is always git reflog --date=relative -n 50. The output lists every move HEAD has made for 90 days, with timestamps. Find the entry that looks like the state you want — usually the one right before the destructive command. Each entry's hash is a real commit you can return to. Do not run more destructive commands until you have identified the rescue target.

Anchoring is next. git switch -c rescue HEAD@{N} creates a new branch pointing at the lost tip. From there, evaluate: is this exactly what was lost, or are some commits missing? Run git log rescue --oneline and confirm. Once you have a branch holding the lost work, the disaster is over — you can choose how to integrate. git reset --hard rescue on the original branch puts everything back. Or git cherry-pick specific lost commits onto current main. Or just keep the rescue branch as a parallel record while you continue.

Three common scenarios. Bad pull merge — accidental merge commit instead of the linear history you wanted. git reset --hard ORIG_HEAD rewinds to before the pull; you can then git pull --rebase for the linear version. Bad rebase — rebase produced a mess or has unresolvable conflicts mid-way. git rebase --abort rewinds to before the rebase. If you committed the bad rebase result, git reflog + git reset --hard HEAD@{N} recovers. Bad force-push — overwrote a teammate's work. Their reflog still has it; have them git push --force-with-lease from a state they hold, or recover via HEAD@{N} from your reflog if you saw their work pre-force-push.

Code

Generic recovery procedure·bash
# 1. STOP. Do not run any more destructive commands.

# 2. Inspect reflog:
git reflog --date=relative -n 50

# 3. Identify the state you want — usually the one right before
#    the destructive command. Note its HEAD@{N} or hash.

# 4. Anchor the lost tip on a rescue branch:
git switch -c rescue HEAD@{3}        # use the right N

# 5. Verify:
git log rescue --oneline -n 10

# 6. Choose how to integrate:
#    - back to the original branch:
git switch original-branch
git reset --hard rescue

#    - or cherry-pick specific lost commits:
git cherry-pick rescue~2 rescue~1 rescue
Common scenario commands·bash
# Bad pull that created an unwanted merge commit:
git reset --hard ORIG_HEAD
git pull --rebase                    # try again, linear

# Mid-rebase mess — bail out:
git rebase --abort

# Already-committed bad rebase result:
git reflog
git reset --hard HEAD@{N}            # before the rebase

# Recovery of a force-pushed branch (teammate's work overwritten):
git reflog                            # find your last fetched view
git switch -c rescue-teammate HEAD@{N}
git push --force-with-lease origin rescue-teammate

External links

Exercise

On a scratch branch with at least 5 commits, deliberately destroy work three ways: (1) git reset --hard HEAD~3, (2) start a rebase and bail out mid-conflict with git rebase --abort, (3) git push --force a rewritten branch then recover via reflog. After each, use git reflog to find the lost tip and restore it. Note in writing which recovery felt scariest before you knew the procedure.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.