The Hook (The "Byte-Sized" Intro)
You ran git stash clear and wiped out 5 stashes. The reflog for stash is now empty. Game over? Not quite. Stashes are merge commits under the hood, and git fsck can find them as dangling objects. This is the advanced recovery that works when reflog fails — your last line of defense.
📖 What is Recovering Stash Mistakes (Advanced)?
When basic reflog recovery fails (e.g., after git stash clear or enough time has passed), you can use git fsck to scan the Git object database for dangling commits that represent lost stashes.
Conceptual Clarity
Stash internals — what Git actually stores: A stash entry is a special merge commit with 2-3 parents:
- Parent 1: The commit HEAD was on when you stashed
- Parent 2: The index (staging area) state
- Parent 3: Untracked files (if
stash -uwas used)
This structure means git fsck can find them as dangling merge commits.
Recovery tools comparison:
| Tool | When to Use | Finds Stashes? |
|---|---|---|
git reflog show stash | Stash reflog exists | ✅ If not expired |
git fsck --unreachable | Reflog empty or expired | ✅ Scans entire object DB |
git fsck --dangling | Same as above (alternative) | ✅ Only truly dangling |
Real-Life Analogy
Basic recovery (reflog) is like checking your browser's "Recently Closed Tabs." Advanced recovery (fsck) is like running disk recovery software — it scans the entire drive for fragments of deleted data. Slower, but catches what the quick methods miss.
Visual Architecture
Why It Matters
- Last resort:
fsckworks when reflog is empty — it scans the raw object database. - Understanding internals: Knowing stashes are merge commits helps you identify them in fsck output.
- Time-limited: Objects are eventually garbage collected (~30 days).
- Professional skill: Deep recovery knowledge is rare and valuable.
Code
# ─── When reflog has entries ───
git reflog show stash
# If entries exist, pick the SHA and apply:
git stash apply abc1234
# ─── When reflog is empty: use fsck ───
git fsck --unreachable | grep commit
# Output:
# unreachable commit a1b2c3d4...
# unreachable commit e5f6g7h8...
# unreachable commit i9j0k1l2...
# ─── Inspect each dangling commit ───
git show a1b2c3d4
# Look for:
# - "WIP on branch: ..." in the commit message → This is a stash!
# - Your changes in the diff
# ─── Apply the found stash ───
git stash apply a1b2c3d4
# Or create a branch:
git branch recovered-stash a1b2c3d4
# ─── One-liner: find all stash-like commits ───
git fsck --unreachable | \
awk '/commit/ {print $3}' | \
xargs -I {} git log -1 --format="%H %s" {} | \
grep "WIP on"
# Lists all dangling stash commits with their messages
# ─── Prevent future loss: backup before clear ───
git stash list > stash-backup.txt
git log --all --oneline $(git stash list | \
awk -F: '{print $1}') >> stash-backup.txtKey Takeaways
- Stashes are merge commits internally —
fsckcan find them as dangling objects. - Look for "WIP on" in dangling commit messages to identify stashes.
git fsck --unreachable | grep commitis your recovery command when reflog fails.- Act within ~30 days before garbage collection permanently removes the objects.
Interview Prep
-
Q: How are stashes stored internally in Git? A: Stashes are stored as special merge commits with 2-3 parents. Parent 1 is the HEAD commit at stash time, parent 2 is the staging area state, and parent 3 (if
-uwas used) contains untracked files. -
Q: How would you recover a stash after
git stash clear? A: Rungit fsck --unreachable | grep committo find dangling commits. Inspect each withgit show <sha>— stash commits have "WIP on" in their message. Once found,git stash apply <sha>restores the changes. -
Q: Why can
fsckfind stashes that reflog cannot? A:git stash clearremoves stash reflog entries but doesn't delete the underlying commit objects from the database.fsckscans the raw object database directly, finding commits that have no references pointing to them.