Git Stash: Save and Restore Work in Progress
- git stash push -m 'description' β always add a message. Unnamed stashes become mystery boxes within 24 hours.
- Use git stash -u to include untracked files; without it, new files stay in your working directory when you switch branches.
- Prefer git stash apply over pop when conflicts are possible β pop deletes the stash before you resolve conflicts, leaving you with no backup.
Stash is one of those Git features that feels like magic the first time you use it and becomes invisible muscle memory after a month. The command is simple; the failure modes are what trip people up.
I've seen developers lose hours of work to three specific stash mistakes: popping a stash onto the wrong branch, stashing without saving untracked files and losing them on a git clean, and accumulating a 15-entry stash stack with zero idea what's in any of them. This guide covers the command, the options that matter, and the mental model that prevents all three.
Basic Stash: Save and Restore Work
The core workflow is three commands. git stash shelves everything in your working directory and index that differs from HEAD. git stash pop restores the most recent stash and removes it from the stack. git stash apply restores without removing β useful when you want to apply the same stash to multiple branches.
One thing that surprises developers coming from other VCS systems: git stash by default only stashes tracked files. If you created a new file that hasn't been git add-ed yet, it won't be stashed. It'll sit there in your working directory when you switch branches, which can lead to unintended commits on the wrong branch. Use git stash -u (or --include-untracked) to include new files.
The stash is a stack β each git stash pushes a new entry. git stash pop pops the top (most recent). This is correct behaviour for the common case but becomes confusion when you stash, do some more work, stash again, and then try to figure out which stash has what.
# Save current work to stash (tracked files only) git stash # Save with a descriptive message β always do this git stash push -m "WIP: payment retry exponential backoff" # Include untracked files (new files not yet git add'd) git stash push -u -m "WIP: new PaymentRetryService class" # Restore most recent stash AND remove it from the stack git stash pop # Restore most recent stash but KEEP it in the stack git stash apply # List all stashes git stash list # Output: # stash@{0}: On feature/payment-retry: WIP: payment retry exponential backoff # stash@{1}: On main: WIP: hotfix debug logging # Restore a specific stash by index git stash pop stash@{1} git stash apply stash@{1} # See what's in a stash before applying git stash show stash@{0} git stash show -p stash@{0} # Full diff
# git stash list:
stash@{0}: On feature/payment-retry: WIP: payment retry exponential backoff
stash@{1}: On main: WIP: hotfix debug logging
# git stash show stash@{0}:
src/main/java/io/thecodeforge/payment/PaymentRetryService.java | 47 +++++++++
1 file changed, 47 insertions(+)
Stash Pop vs Apply: When to Use Each
The difference matters more than most tutorials let on.
git stash pop = apply + delete from stack. Use this 95% of the time. The moment you successfully restore your work, the stash entry is gone. Clean, no accumulation.
git stash apply = apply but leave in stack. Use this when: you want to apply the same changes to multiple branches (e.g. a config change you need on both a feature branch and a hotfix branch), or when you're not 100% sure the stash applies cleanly and you want to keep it as a backup while you verify.
There's one critical behaviour difference: if git stash pop encounters a conflict, it still removes the stash from the stack before throwing the conflict. You're now in a conflicted state with the stash gone. This is a Git footgun β you want git stash apply when there's any chance of conflicts, so the stash survives even if the apply fails.
# Scenario: you might have conflicts β use apply, not pop git stash apply stash@{0} # If it applied cleanly with no conflicts, manually drop the stash git stash drop stash@{0} # If there ARE conflicts, resolve them, then drop manually # The stash is still in the stack β you haven't lost anything git status # Shows conflicted files # ... resolve conflicts ... git add . git stash drop stash@{0} # Now safe to remove # Apply same stash to two branches git checkout feature/branch-a git stash apply stash@{0} # Applied to branch A β stash still exists git checkout feature/branch-b git stash apply stash@{0} # Applied to branch B too git stash drop stash@{0} # Now clean up # Clear ALL stashes (nuclear β use with care) git stash clear
Auto-merging src/main/java/io/thecodeforge/payment/PaymentService.java
CONFLICT (content): Merge conflict in src/main/java/io/thecodeforge/payment/PaymentService.java
# Stash is still in stack β safe to resolve then drop
Stashing Partial Changes and Specific Files
Sometimes you only want to stash part of your changes β for example, you've been working on two unrelated things in the same branch (happens to everyone, don't judge) and you want to commit one thing cleanly before stashing the other.
git stash push -- <path> stashes only the specified files. Everything else stays in your working directory.
git stash push -p (patch mode) drops you into an interactive hunk-by-hunk selection β exactly like git add -p. You choose yes/no for each chunk. This is powerful but slow for large changesets.
# Stash only specific files git stash push -m "WIP: retry config" -- src/main/java/io/thecodeforge/payment/RetryConfig.java # Stash multiple specific files git stash push -m "WIP: two related files" \ -- src/main/java/io/thecodeforge/payment/RetryConfig.java \ -- src/main/java/io/thecodeforge/payment/RetryPolicy.java # Interactive patch mode β choose which hunks to stash git stash push -p -m "WIP: partial changes" # Git shows each change hunk and asks: stash this hunk? [y/n/q/a/d/?] # Create a branch from a stash (useful for long-lived stashes) git stash branch feature/retry-config stash@{0} # Creates new branch at the commit where you stashed, applies the stash, drops it
# Only RetryConfig.java was stashed
# RetryPolicy.java remains in working directory
| Command | Effect | Stash Removed? | Best For |
|---|---|---|---|
| git stash | Stash tracked files | N/A | Quick context switch |
| git stash -u | Stash tracked + untracked | N/A | When you have new files |
| git stash pop | Apply + remove from stack | Yes | Normal restore β 95% of cases |
| git stash apply | Apply, keep in stack | No | Risky merges or multi-branch apply |
| git stash drop | Remove without applying | Yes | Discard stash you no longer need |
| git stash clear | Remove ALL stashes | Yes (all) | Spring cleaning β careful |
| git stash branch <name> | Create branch from stash | Yes | Long-lived stashes that deserve a branch |
π― Key Takeaways
- git stash push -m 'description' β always add a message. Unnamed stashes become mystery boxes within 24 hours.
- Use git stash -u to include untracked files; without it, new files stay in your working directory when you switch branches.
- Prefer git stash apply over pop when conflicts are possible β pop deletes the stash before you resolve conflicts, leaving you with no backup.
- git stash branch <name> <stash> converts an old stash into a proper branch β the right move when a stash has grown into more work than you expected.
- Stashes are global to the repo, not scoped to a branch β applying a stash on the wrong branch is an easy mistake with sometimes messy consequences.
β Common Mistakes to Avoid
- βRunning git stash without -u and losing new (untracked) files β they stay in the working directory when you switch branches and get committed to the wrong place.
- βAccumulating a deep stash stack with no messages β stash@{7} with no description is useless. Always use git stash push -m 'description'.
- βUsing git stash pop when conflicts are possible β pop deletes the stash before the conflict is resolved. Use apply + manual drop instead.
- βForgetting that git stash is per-repository, not per-branch β stashes don't belong to branches. You can pop a stash made on feature/x onto main, which is sometimes intentional and sometimes a very bad day.
- βRunning git stash clear thinking it only clears 'old' stashes β it removes everything with no confirmation and no recovery except reflog.
Interview Questions on This Topic
- QWhen would you use git stash apply instead of git stash pop?
- QA developer stashed changes, switched branches, and now can't find which stash contains their work. How do they find and apply the right one?
- QExplain how git stash stores its data internally. Is a stash a commit?
- QYou have three stashes and want to apply the second one without disturbing the others. What command do you run?
Frequently Asked Questions
What is the difference between git stash pop and git stash apply?
git stash pop applies the stash and immediately removes it from the stash stack. git stash apply applies it but leaves it in the stack. Use apply when there's a chance of merge conflicts (so the stash survives if the apply fails) or when you want to apply the same stash to multiple branches.
Does git stash save untracked files?
No, by default git stash only saves tracked files that have been modified. To include untracked files (new files not yet added with git add), use git stash push -u or git stash push --include-untracked.
How do I see what's in a stash before applying it?
Run git stash show stash@{N} for a summary of changed files, or git stash show -p stash@{N} for the full diff. Replace N with the stash index from git stash list.
Can I recover a stash I accidentally dropped?
Sometimes. Run git fsck --no-reflogs | grep commit to find dangling commit objects (stash entries are commits internally). You can then run git stash apply <hash> on any hash that looks like your lost stash. This works within the gc.reflogExpire window (default 30 days) as long as you haven't run git gc.
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.