Recovering a dropped stash Jump to heading

git stash drop and git stash clear both report success and say nothing about what they removed, which is how an afternoon’s work disappears in one keystroke. The good news is that neither command deletes anything: they remove a reference, and the commits behind it stay in the object database until garbage collection runs. Recovery is reliable if you act before that happens, and this recipe covers both routes, within stashing and work-in-progress recovery.

When to use this approach Jump to heading

  • A stash entry was dropped and you need it back.
  • git stash clear removed a stack containing something wanted.
  • A pop conflicted and the entry vanished along with the work.
  • Someone reset a branch and the stashed work went with it.
  • If garbage collection has already run with --prune=now, recovery may not be possible — try anyway, but prepare for the answer.

Step 1 — Stop, before doing anything else Jump to heading

Every command that writes to the object database brings collection closer, and some trigger it directly.

# Do NOT run any of these until recovery is complete:
#   git gc
#   git prune
#   git repack
#   git clone over the directory
#   anything that says "cleaning up"
# Confirm collection has not already run
ls -la .git/objects/pack/ | tail -3
git count-objects -v | grep -E 'count|garbage'
# Verification: a high loose-object count is good news — nothing has been packed away
git count-objects -v | grep '^count:'
The window in which recovery worksDropping a stash removes only the reference. The commits remain reachable through the stash reflog for the reflog expiry period, and remain in the object database as unreachable objects until garbage collection prunes them — which is when recovery stops being possible.Droppedreference removedt+0Reflog routegit reflog stashminutesfsck routeunreachable commitsdaysGoneobjects removedafter gc --prunethe last point is the only one that is actually irreversible

Step 2 — Try the stash reflog first Jump to heading

The stash ref keeps its own reflog, and a dropped entry is usually still in it.

git reflog stash
# Each line names a commit; inspect them to find the right one
git reflog stash --format='%H %gd %gs' | while read -r sha rest; do
  printf '%s  %s\n' "$sha" "$(git show --stat --format='%s' "$sha" | head -1)"
done
# Apply the one you want
git stash apply '<sha-from-above>'
# Verification: the working tree now contains the recovered changes
git status --short | head
git diff --stat

Step 3 — Fall back to searching unreachable commits Jump to heading

If the reflog entry is gone too — after stash clear, or after reflog expiry — the commits are still there, just unreferenced.

git fsck --unreachable --no-reflogs 2>/dev/null | awk '$2 == "commit" {print $3}' > /tmp/orphans.txt
wc -l /tmp/orphans.txt
# Stash entries are recognisable: their subject starts with "WIP on" or "On <branch>"
while read -r c; do
  subj=$(git log -1 --format='%s' "$c")
  case "$subj" in "WIP on"*|"On "*) printf '%s  %s  %s\n' "${c:0:8}" \
    "$(git log -1 --format='%ad' --date=short "$c")" "$subj" ;; esac
done < /tmp/orphans.txt
# Inspect a candidate before applying it
git show --stat "<candidate>"
git show "<candidate>" -- src/payments/refund.ts | head -30
# Verification: the tree contains what you remember writing
git ls-tree -r --name-only "<candidate>" | head
Two recovery routes, in order of reliabilityThe stash reflog holds dropped entries and is exact. When it has been cleared, fsck lists every unreachable commit and stash entries are identifiable by their subject line. Both end at the same place: applying the commit or turning it into a branch.Stash reflogexact, labelledfsck orphansbroader, identifiableInspectshow --statBranch from itcannot be lost againthe fourth box is the step people skip, and it is why the same work gets lost twice

Step 4 — Turn the recovery into a branch immediately Jump to heading

Applying a recovered stash into the working tree leaves it exactly as exposed as it was before.

git branch recovered/refund-window '<sha>'
git switch recovered/refund-window
# Or, keeping the original base, which usually applies more cleanly
git stash branch recovered/refund-window '<sha>'
# Push it, so the recovery survives the next mistake
git push -u origin recovered/refund-window
# Verification: the work is now on a branch, on the remote
git log --oneline -1 origin/recovered/refund-window

SAFETY WARNING — do not apply a recovered stash on top of unrelated uncommitted work. If the apply conflicts you will have two sets of changes interleaved with conflict markers and no clean state to return to. Commit or stash what you have first — to a branch this time — and apply the recovery into a clean tree.

Step 5 — Make the next loss impossible rather than recoverable Jump to heading

# Always label, so the stack is reviewable before anything is cleared
git stash push -m 'refund window: clamp half-done'
# Check the stack before any destructive command
git stash list && echo "--- review the above before clearing"
# Move anything older than a day onto a branch
git stash list --format='%gd %ci %gs' | while read -r ref date rest; do
  age=$(( ( $(date +%s) - $(date -d "$date" +%s) ) / 86400 ))
  [ "$age" -ge 1 ] && echo "$ref is $age day(s) old: $rest"
done
# Verification: nothing older than a day remains on the stack
git stash list | wc -l
A stash against a pushed branchA stash exists on one machine, is not pushed, has no backup, and is removed by a single unconfirmed command. A branch pushed to the remote survives every one of those, and costs one extra command to create.Stash entryPushed branchexists onone machinethe remote tooremoved byone unconfirmed commanda deliberate deletevisible to toolsnoyescost to createone commandtwothe second row is why this page exists

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

How long do dropped stashes remain recoverable? Jump to heading

Reflog entries for the stash ref follow the usual expiry — ninety days for reachable entries and thirty for unreachable ones by default — and the underlying objects survive until garbage collection prunes them, which happens automatically when loose objects accumulate. In practice you have days, not weeks, and the only safe assumption is that you have until the next maintenance run.

Does this work after git stash clear? Jump to heading

Yes, by the fsck route. Clear removes the ref and its reflog in one go, so the reflog lookup finds nothing, but the commits are untouched and appear as unreachable objects. That is the case Step 3 exists for.

What if fsck lists hundreds of orphaned commits? Jump to heading

Filter by subject, as in Step 3 — stash entries have a distinctive one — and then by date. If several candidates remain, git show --stat on each is quick, and the file list is usually enough to identify the right one without reading any diffs.