What is git stash and when to use it?
git stash temporarily saves your uncommitted working directory and staged changes to a stack, clears your working tree to match the current commit, and lets you reapply them later.
Theory
TL;DR
- Think of it like folding half-written sticky notes into a drawer: work pauses exactly where it is, desk clears for the urgent task, notes unfold back unchanged
- Saves both staged and unstaged changes in one command; add
-uto capture untracked files too - Core loop: stash, switch branch or pull, pop
popapplies the stash and drops it from the stack;applykeeps it there- Use stash when uncommitted work blocks you; skip it when changes are stable enough to commit
Quick example
# On feature branch with uncommitted changes
git stash push -m "WIP: login validation"
# Output: Saved working directory and index state WIP: login validation
git status
# On branch feature, nothing to commit, working tree clean
git stash pop
# Restores everything exactly as it was
# Output: Dropped refs/stash@{0}That is the whole pattern. Stash cleans your tree, you do what needs doing, pop brings everything back.
When to use
Stash fits a few specific situations well:
- Mid-feature and an urgent bugfix lands: stash on the feature branch, checkout main, fix and commit, come back, pop
- Uncommitted changes block
git pull: stash, pull, pop (handle conflicts after if they come up) - Context switch is too fast for a proper commit: use a descriptive stash message instead of a half-baked commit with "WIP" in the title
Skip stash if you expect the reapplication to conflict with incoming changes - create a branch instead. Also skip it if changes are already stable; just commit.
How git stash works internally
Git creates two commits under the hood. The first captures your index (staged files) as a tree. The second captures your working directory diff on top of that. Both get stored in .git/refs/stash as a reflog stack, where stash@{0} is always the newest entry.
git stash push calls git commit-tree with plumbing commands to bundle these states, then resets HEAD, index, and working tree to the base commit. git stash pop replays the diff and removes the reflog entry if there are no conflicts.
This is why stash conflicts happen: the stored diff was created relative to one base commit, but by the time you pop, the base may have moved.
Common mistakes
Forgetting -u when you have untracked files:
npm install new-dep # Creates untracked files
git stash # Ignores them by default
git checkout other # Those files stay behind or cause confusionFix: git stash -u. Or make sure .gitignore properly covers what you do not need tracked.
Stash then git pull --rebase without popping first:
git stash
git pull --rebase origin main # Rewrites base commit history
git stash pop # Stash was made against the old base, conflicts likelyThe stash holds a diff relative to the original base commit. After rebase that base moved. Pop before rebase, or rebase first and pop after.
Assuming pop always cleans up on conflict:
git stash pop
# CONFLICT (content): Merge conflict in file.js
# Applying stash failed, stash remainsWhen pop hits a conflict, it applies changes with conflict markers but does NOT drop the stash. The safer path: git stash apply, resolve manually, then git stash drop.
Dropping the wrong stash by index:
git stash list
# stash@{0}: WIP: new feature
# stash@{1}: WIP: older experiment
git stash drop stash@{1} # Indices shift on every push or popAlways run git stash list right before dropping. With many entries, git stash branch new-branch stash@{0} is safer than juggling indices.
Real-world usage
- React contributors stash WIP hooks before
git pull upstreamto keep merges clean (see the CONTRIBUTING.md workflow) - Node.js contributors stash uncommitted benchmarks mid-pull when CI fixes land
- VS Code extension developers stash partial TypeScript changes between branch switches
git stashvsgit worktree: stash for quick context switches; worktree when you need two branches open in parallel for a longer stretch
Follow-up questions
Q: What is the difference between git stash apply and git stash pop?
A: apply reapplies the stash but keeps it on the stack. pop applies and drops it. Use apply when you are not sure the reapplication will go cleanly, so you have a fallback.
Q: How does git stash handle untracked files?
A: By default it ignores them. Pass -u or --include-untracked to stash untracked files. Pass -a or --all to also include files matched by .gitignore.
Q: What happens if git stash pop has a conflict?
A: Git leaves conflict markers in the affected files and the stash stays on the stack. Pop only drops the entry on a clean apply. Resolve the conflicts, stage the files, then git stash drop.
Q: Can you stash during a rebase or merge conflict?
A: During an active merge conflict git stash will fail. Use git stash branch new-branch stash@{0} to create a branch from the stash state instead of applying it directly.
Q: How is the stash stored internally? Walk through the commit graph.
A: Two commits: one for the index state (i), one for the working directory diff on top (w). Both point to HEAD at stash time. The reflog at .git/logs/refs/stash tracks the stack. stash@{0} is the w commit, its parent is i, and i points back to the original HEAD.
Q: What is the safest workflow when git stash pop keeps conflicting?
A: Run git stash branch new-branch stash@{0}. It creates a branch at the exact commit where the stash was made, applies the stash there (no base mismatch), and drops it if clean. Then merge or rebase that branch the normal way.
Examples
Switching branches mid-feature
You are editing Login.jsx and have utility changes staged when a production issue comes in.
# Staged utils, unstaged Login.jsx changes
git stash push -u -m "WIP: login form validation"
# -u captures any untracked config files too
git checkout main
git checkout -b hotfix/auth-token
git commit -m "Fix: expired token not clearing session"
git push origin hotfix/auth-token
git checkout feature/user-auth
git stash pop
# Login.jsx and utils restored exactly as leftIf a conflict appears after pop, Git marks the file with <<<<<<< markers. Resolve them, stage, then run git stash drop to clear the entry.
Stash conflict after upstream changes
This one trips up experienced developers. Staged file A, unstaged file B, untracked file C. Someone pushes a change to B while your stash sits there.
echo "A" > A.txt && git add A.txt
echo "B" > B.txt
echo "C" > C.txt # untracked
git stash push -u -m "partial work"
# Meanwhile on remote: B.txt gets a new commit
git pull
git stash pop
# CONFLICT (content): Merge conflict in B.txt
# Applying stash failed, stash remains
# Do NOT run git stash drop yet
# Resolve B.txt manually, then:
git add B.txt
git stash drop # Now safe to removeA.txt and C.txt restored cleanly. Only B.txt conflicted because both the remote commit and the stash touched the same file. I have seen developers panic at "stash remains" thinking they lost work. Nothing is lost; Git just needs the conflict resolved before it can clean up.
Stash and rebase: the right order
# Wrong order
git stash
git pull --rebase origin main # Base moves without your changes
git stash pop # Stash diff now points to old base, conflicts very likely
# Right order
git stash
git fetch origin
git rebase origin/main # Rebase first on fetched state
git stash pop # Pop onto the new base cleanlyThe stash stores a diff relative to the base commit at the moment you stashed. Rebase changes that base. Keep the order right and you avoid most stash-related headaches.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.