You ran git stash, switched to main to review a PR, switched back with git checkout feature/login, ran git stash pop — and now git stash list is empty and your half-finished changes are nowhere to be found.
Fastest fix: first run git status and git diff. If you see your modified files, the stash already applied to the working tree and nothing is lost. If the tree is clean, the stash commit still exists as a dangling object — recover its SHA with git fsck --no-reflog | grep commit, then git stash apply <SHA>. By default Git keeps unreachable objects for at least 30 days (and reachable reflog entries for 90), so recovery is almost always possible.
Why this works: a stash is stored as a real commit object. The pointer lives in refs/stash; older entries live in that ref’s reflog. Dropping, popping, or clearing a stash removes the reference, but the commit object survives in the object database until garbage collection prunes it.
Which bucket are you in?
Run these three commands first — they tell you instantly which recovery path you need.
| Command | If you see… | Cause | Go to |
|---|---|---|---|
git status / git diff | Your modified files | Stash already applied (pop succeeded) | Nothing to do |
git stash list | Entries, but for a different branch | Wrong stash popped / multiple stashes | Step 1 |
git reflog stash | Old SHAs, list empty | Stash dropped or popped clean | Step 2 |
git fsck --no-reflog | dangling commit <sha> | Reflog entry gone too | Step 3 |
| Nothing anywhere | Untracked files removed by git clean | Files were never in the stash | Step 5 |
Common causes
Ordered by hit rate, highest first.
1. git stash pop applied successfully and dropped the stash automatically
git stash pop is git stash apply followed by git stash drop. If the apply succeeds with no conflict, the stash entry is removed immediately — but your changes are now on disk in the working tree. They were not lost, just applied.
How to spot it: run git status and git diff. Modified files present = stash applied, nothing lost.
2. git stash drop or git stash clear run by mistake
A copy-paste slip, muscle memory, or a shell alias ran git stash drop instead of git stash show. git stash clear removes every entry at once.
How to spot it: git stash list is empty. Note that after a drop, the dropped entry is usually gone from the stash reflog too — so if git reflog stash is also empty, jump straight to git fsck in Step 3.
3. A pop hit a conflict and the tree was cleaned by hand
This is the one most people misremember. In modern Git (and every version for the last decade), git stash pop does NOT drop the stash when it hits a conflict — the official docs state: “Applying the state can fail with conflicts; in this case, it is not removed from the stash list.” So if the pop conflicted, your stash is still in git stash list.
The actual loss happens when, faced with a conflicted tree, the user runs git checkout -- ., git reset --hard, or git stash drop to “clean up,” wiping the half-applied changes. The stash commit still exists by SHA.
How to spot it: git stash list still shows the entry (look there first); if you already discarded it, recover via Step 2/3.
4. The stash you popped belonged to a different branch
You stashed on feature/login, forgot, switched to feature/payments, and stashed again there. Switching back, git stash list shows the payments stash at stash@{0} and the login stash at stash@{1}, so a plain git stash pop grabs the wrong one. Stashes are global to the repo, not per-branch.
How to spot it: git stash list shows the branch in each message: stash@{0}: WIP on feature/payments: .... Pop the right index explicitly: git stash pop stash@{1}.
5. A git worktree doesn’t see the main worktree’s stash
refs/stash is per-worktree by default. A stash created in the main worktree is not listed inside an added worktree (and vice versa), so it looks lost.
How to spot it: git worktree list shows multiple entries. The stash was created in a different worktree’s context — run git stash list from that worktree’s directory.
6. git clean -fd removed untracked files the stash never held
Plain git stash stashes only tracked, modified files. New untracked files are not included unless you pass -u (--include-untracked) or -a (--all). If your missing work was brand-new files, git clean -fd deleted them outright and the stash never had them.
How to spot it: the lost work consisted of files you had never git add-ed. Confirm what a stash actually held with git stash show -p <ref> (look for new file: lines).
Shortest path to fix
Step 1: Check whether the stash is already applied or sitting on another branch
git status
git diff
git stash list
If git diff shows your changes, you’re done. If git stash list shows the entry (possibly under a different branch), apply the right one explicitly:
git stash apply stash@{1}
Step 2: Find dropped stash commits in the stash reflog
git reflog stash --date=iso
# equivalent: git reflog show refs/stash --date=iso
Each line gives a SHA, e.g. abc1234 refs/stash@{0}: WIP on feature/login: 3fa1b2c add session token. Note the SHA (call it STASH_SHA). Inspect before applying:
git stash show -p STASH_SHA # full patch
A clean git stash drop often empties this reflog, so if there’s nothing here, go to Step 3.
Step 3: Find dangling stash commits with git fsck
When the reflog is gone, the stash commit is a dangling object. List dangling commits and grep for the WIP on summary stash commits carry:
git fsck --no-reflog | awk '/dangling commit/ {print $3}' | while read sha; do
printf '%s ' "$sha"
git show --no-patch --format='%s' "$sha"
done | grep 'WIP on'
A stash commit has 2–3 parents (HEAD at stash time, the index, and optionally an untracked-files commit if -u/-a was used), which helps confirm you found the right object.
Step 4: Restore the recovered stash
# Apply the recovered SHA straight to the working tree:
git stash apply STASH_SHA
Or re-register it as a proper stash entry first (then it shows up in git stash list):
git stash store -m "restored dropped stash" STASH_SHA
git stash pop
(git stash store is the porcelain for this; git update-ref refs/stash STASH_SHA does the same at the plumbing level.)
Step 5: Handle a pop that left conflicts
If a pop conflicted and you want to keep going (do NOT clean the tree — the stash is still in the list):
git checkout --theirs src/login.ts # or resolve by hand, then:
git add src/login.ts
git stash drop # only after every conflict is resolved
Step 6: Recover untracked files removed by git clean
Untracked files deleted by git clean are not in Git’s object database, so reflog/fsck cannot bring them back. Your only options are editor local history or a filesystem snapshot:
# VS Code: right-click the file (or its folder) > Open Timeline > pick a Local History entry
# JetBrains: right-click in Project view > Local History > Show History
# macOS: enter Time Machine for the folder; Linux/ZFS: ls .zfs/snapshot/
How to confirm it’s fixed
git status # your files show as modified / staged again
git diff # the expected lines are back
If you re-registered the stash with git stash store, also confirm git stash list shows it before you pop or drop it.
Prevention
- Prefer
git stash applyovergit stash pop— apply keeps the entry as a safety net even after a successful apply; drop it manually once you’re happy. - Name your stashes:
git stash push -m "login form WIP: session token handling"sogit stash listis readable. - Include untracked files:
git stash push -u(or-afor ignored + untracked too) so new files aren’t left behind. - Dry-run before cleaning:
git clean -nfdprints what would be deleted without deleting it. - Extend the recovery window:
git config --global gc.reflogExpireUnreachable 90.days(the default for unreachable/dropped entries is 30 days; reachable reflog entries default to 90). - Use
git worktree add ../login feature/loginto work on several branches at once instead of stash-checkout-stash cycles. - For anything you’d be sad to lose, commit it instead of stashing:
git commit -m "WIP: do not merge". Commits are reachable from a branch and easy to find withgit log.
FAQ
Q: Does git stash pop delete my stash if it hits a merge conflict?
A: No. Per the official docs, when the apply fails with conflicts the entry “is not removed from the stash list.” Check git stash list — it’s still there. Resolve the conflicts, then git stash drop manually. The usual cause of real loss is cleaning the conflicted tree by hand (e.g. git reset --hard).
Q: Can I recover a stash that was dropped more than 30 days ago?
A: Maybe, if git gc hasn’t pruned the object yet (loose objects default to a 2-week prune grace period, but unreferenced stash objects often survive far longer until a gc runs). Try git fsck --unreachable --no-reflog and inspect each commit <sha> with git show. There’s no guarantee after garbage collection.
Q: I dropped the stash but git reflog stash is empty. Now what?
A: A successful git stash drop removes the entry from the stash reflog, so the reflog won’t help. Use git fsck --no-reflog (Step 3) to find the dangling commit by its WIP on message, then git stash apply <sha>.
Q: How do I see a stash’s full diff without applying it?
A: git stash show -p stash@{0} prints the full patch. Use --stat instead of -p for a file summary, or git stash show -p STASH_SHA for a recovered SHA.
Q: Why does my stash show up in one worktree but not another?
A: refs/stash is per-worktree. Run git stash list from the directory of the worktree where you created the stash (git worktree list shows them all).
Q: Are stashes shared across clones or pushed to the remote?
A: No. Stashes are purely local — git push/git fetch never touch refs/stash. To share WIP across machines, commit to a draft branch (git switch -c draft/my-feature) and push that.