Stash — Save Work Without Committing
git stash shelves uncommitted changes so you can switch context (pull, switch branches, hotfix) and come back. Stashes are stored as commits in a hidden ref; they’re not lost when you stash.
The basic flow
git stash # save tracked-file changes; working tree clean
git stash list # show stashes
# stash@{0}: WIP on feature: a1b2c3 Add user model
# stash@{1}: On main: WIP fix bug
git stash pop # apply most recent + remove from list
git stash apply # apply most recent + keep in list
git stash drop # remove most recent without applying
git stash clear # remove all stashes
pop is the lazy default. apply is safer when you might want to re-apply on multiple branches.
What gets stashed by default
| Files | Stashed by default? |
|---|---|
| Tracked, modified | yes |
| Tracked, staged | yes |
| Untracked | no — easy to forget |
Ignored (.gitignore) |
no |
Common bug: stash, switch branch, panic that “my new file is gone.” It’s still in the working tree because untracked files weren’t stashed.
To include untracked:
git stash -u # also stash untracked
git stash --include-untracked # same thing
git stash -a # also stash IGNORED files (rarely useful)
Naming stashes
Empty stashes are confusing in a list of 5. Always name:
git stash push -m "WIP refactoring serializer"
git stash push -u -m "experimenting with new dep"
(stash push is the modern form of stash save.)
Stash specific files
git stash push -m "just the user files" user.py user_serializer.py
Anything not listed stays in the working tree.
For a partial stash within a file:
git stash push -p # interactive hunk-by-hunk
Pop vs apply — the practical difference
git stash apply stash@{2} # apply stash 2, keep it
git stash pop stash@{2} # apply stash 2, drop it
pop automatically drops. But: if the apply has conflicts, pop keeps the stash anyway (so you don’t lose work). Resolve the conflicts, git stash drop when done.
Apply on a different branch
A common workflow trick: stash on main, switch to feature, apply.
git stash
git switch feature
git stash pop
Useful when you started work on the wrong branch.
Inspect stash contents
git stash show stash@{0} # summary
git stash show -p stash@{0} # full diff
git stash show stash@{0} --name-only
Convert a stash to a branch
When the stash represents real work that should become a feature:
git stash branch new-feature stash@{0}
Creates new-feature from the commit the stash was based on, applies the stash, drops it. Useful if the underlying branch has moved.
How stash actually works
A stash is a commit (actually two: one for index, one for working tree) parented at the current HEAD, stored at refs/stash and pushed onto the stash stack.
HEAD ← where you were
│
└── stash@{0} commit ← what you stashed
Because they’re real commits, dropped stashes survive in the object store until garbage collection. Recoverable via git fsck --no-reflog | grep dangling. See 05_reflog_recovery.md.
Conflicts on pop
git stash pop
# Auto-merging file.py
# CONFLICT (content): Merge conflict in file.py
The stash stays in the list. Resolve like any merge conflict, git add, git stash drop to remove the stash.
Common patterns
“Need to pull but have local changes”
git stash
git pull
git stash pop
Or git pull --rebase --autostash (configure once: git config --global rebase.autoStash true) — git stashes/unstashes around the pull automatically.
“Forgot to start on a new branch”
git stash -u # save everything including untracked
git switch -c new-feature
git stash pop
“Want to test main without losing my work”
git stash -u -m "wip"
git switch main
# ... test ...
git switch - # back to previous branch
git stash pop
When NOT to use stash
- Long-term parking. Stashes are a dirty drawer; old ones get forgotten. After a day or two, commit to a WIP branch instead.
- Shared work. Stashes are local — can’t share via push. Commit (even a
wip:commit) and push. - Work you want to keep cleanly. A WIP commit on a branch is more discoverable than a stash.
Common interview confusions
- “Stash includes everything in my working tree.” — by default, only tracked files. Untracked needs
-u. - “
git stash popalways removes the stash.” — except when the apply conflicts; then it stays. - “Stashes are lost when you delete them.” — orphaned but recoverable via
git fsckuntil garbage collection. - “Stash is global across repos.” — local to one repo. Each repo has its own stash stack.
Interview angle
- “What does
git stashdo?” — saves uncommitted tracked-file changes to a stack and cleans the working tree.popto re-apply. Doesn’t include untracked files unless-u. - “How do you stash untracked files?” —
git stash -u(or--include-untracked). - “What’s the difference between
stash popandstash apply?” — pop applies and removes from the stack; apply applies but keeps it. Pop also keeps the stash if conflicts arise. - “Stash is on main, you want it on feature — how?” — stash, switch branch, pop. Or
git stash branch new-featureto create a branch from the stash’s base and apply there. - “Stash got dropped accidentally — recoverable?” — usually yes.
git fsck --no-reflog | grep danglingfinds the commit;git stash apply <sha>. Until garbage collection. - “Better alternatives to stash for long-term work?” — commit to a WIP branch (
git switch -c wip-something); discoverable, shareable, doesn’t get lost.