The brief
Deliberately "lose" commits via reset and rebase, then recover them using reflog. Build the muscle memory for the safety net.
Step 1: Setup (5 min)
mkdir reflog-drill && cd reflog-drill
git init
echo "v1" > app.py && git add . && git commit -m "Initial"
echo "v2" > app.py && git commit -am "Improve"
echo "v3" > app.py && git commit -am "Add feature"
echo "v4" > app.py && git commit -am "Refactor"
echo "v5" > app.py && git commit -am "Polish"
git log --oneline
# abc1 Polish
# abc2 Refactor
# abc3 Add feature
# abc4 Improve
# abc5 Initial
Step 2: Lose via reset --hard (10 min)
git reset --hard HEAD~3
# Lost: Polish, Refactor, Add feature
# HEAD now at abc4 Improve
git log --oneline
# abc4 Improve
# abc5 Initial
cat app.py
# v2
The last 3 commits and the v3-v5 content seem gone. But:
git reflog
# abc4 HEAD@{0}: reset: moving to HEAD~3
# abc1 HEAD@{1}: commit: Polish
# abc2 HEAD@{2}: commit: Refactor
# abc3 HEAD@{3}: commit: Add feature
# abc4 HEAD@{4}: commit: Improve
# abc5 HEAD@{5}: commit (initial): Initial
Each operation logged. Restore:
git reset --hard abc1 # the Polish commit
# OR
git reset --hard HEAD@{1} # same effect
git log --oneline
# abc1 Polish
# abc2 Refactor
# abc3 Add feature
# abc4 Improve
# abc5 Initial
cat app.py
# v5
Recovered.
Step 3: Lose via interactive rebase mistake (10 min)
git rebase -i HEAD~3
Mark all as drop (mistake!):
drop abc1 Polish
drop abc2 Refactor
drop abc3 Add feature
Save. Git executes; commits gone:
git log --oneline
# abc4 Improve
# abc5 Initial
Recover via reflog:
git reflog
# Look for: rebase (start): checkout abc4 (pre-rebase state)
# Or: the SHA of where you were before rebase
git reset --hard <pre-rebase-sha>
# Or: git reset --hard ORIG_HEAD (Git sets ORIG_HEAD before destructive ops)
ORIG_HEAD is a convenient shortcut for the position before the last "big" operation.
Step 4: Recover a deleted branch (5 min)
git switch -c feature
echo "feature work" > feature.txt
git add . && git commit -m "Feature commit"
git switch main
git branch -D feature
# Deleted branch feature (was abc7).
git branch
# Only main shown; feature gone
But the commit still exists:
git reflog
# abc7 HEAD@{2}: commit: Feature commit
# ...
git branch feature abc7 # recreate branch at that commit
git switch feature
cat feature.txt
# feature work
Step 5: Use fsck for truly lost commits
Simulate an old loss (in real life, after reflog expired):
git fsck --lost-found
# dangling commit abc8 ...
These are commits not referenced by any branch or in reflog. Investigate:
git show abc8
# See its diff and message
git branch recovered abc8
Step 6: Reflog scope
git reflog # HEAD's reflog
git reflog main # main branch's reflog
git reflog --all # all refs' reflog
Branches have their own reflog. If you reset main and want history of main specifically:
git reflog main
# Specifically tracks main's tip history
Deliverables
Submission contract: upload RECOVERY.md (reflog retention, ORIG_HEAD, fsck --lost-found, what can't be recovered).
100-pt rubric: reset --hard recovery (25) / rebase-mistake recovery via reflog/ORIG_HEAD (25) / deleted-branch recovery (20) / fsck dangling-commit recovery (15) / RECOVERY.md documents limits (15).
upload RECOVERY.md (reflog retention, ORIG_HEAD, fsck --lost-found, what can't be recovered).
reset --hard recovery (25) / rebase-mistake recovery via reflog/ORIG_HEAD (25) / deleted-branch recovery (20) / fsck dangling-commit recovery (15) / RECOVERY.md documents limits (15).
upload RECOVERY.md (reflog retention, ORIG_HEAD, fsck --lost-found, what can't be recovered).
reset --hard recovery (25) / rebase-mistake recovery via reflog/ORIG_HEAD (25) / deleted-branch recovery (20) / fsck dangling-commit recovery (15) / RECOVERY.md documents limits (15).
- A demonstrated recovery from each scenario: reset --hard, rebase mistake, deleted branch.
- A
RECOVERY.mddocumenting:- How reflog records every HEAD movement.
- The 90-day default retention.
ORIG_HEADshortcut.git fsck --lost-foundfor ancient losses.- What CAN'T be recovered (uncommitted/untracked work).
What you'll learn
- Reflog as the universal safety net.
git reset --hard <sha>to restore any prior state.ORIG_HEADafter destructive operations.- Branch reflog vs HEAD reflog.
git fsck --lost-foundfor last-resort recovery.- Why frequent commits make recovery easier.
Stretch
- Set reflog retention:
git config gc.reflogExpire 365.days(1 year). - Experiment with
git gc --prune=nowto see what truly gets deleted (CAUTION: irreversible). - Build a script that creates a daily snapshot tag for extra safety.