Git Stash: How I Stopped Losing Work Mid-Feature (And You Can Too)
Git Stash: How I Stopped Losing Work Mid-Feature (And You Can Too)
I’ll be honest — the first time I discovered git stash, it felt like finding a secret room in a house I’d been living in for years.
I had been hacking on a new API integration for about three hours when Slack lit up: production was throwing 500 errors on the payment endpoint. Classic. I panicked, ran git status, saw 30-odd modified files, and had no clean way out. I didn’t want to commit half-baked code. I didn’t want to throw away three hours of work. I ended up copying my changes to a text file like an animal.
Then I learned about git stash. Never again.
Here’s everything I know about it — including the gotchas that bit me.
What Git Stash Actually Does
git stash snapshots your current working directory — both staged and unstaged changes — and saves that snapshot to a local stack. Your working directory goes back to a clean state (matching the last commit), and you can restore the snapshot whenever you’re ready.
Think of it as a clipboard that survives branch switching.
Working directory (messy)
↓ git stash
Clean working directory + stash stack → [ stash@{0}, stash@{1}, ... ]
↓ git stash pop
Working directory (messy again, where you left off)
Crucially: stashes are local only. They don’t get pushed to a remote. They live on your machine, tied to your local Git repo.
When to Reach for Stash
| Situation | What stash buys you |
|---|---|
| Urgent hotfix while mid-feature | Switch branches cleanly, no half-baked commit |
| Realized you’re on the wrong branch | Move changes over without losing anything |
Need a clean git pull |
Avoid the “please commit or stash” error |
| Want to test something with a clean slate | Temporarily set aside WIP and test the baseline |
| Apply the same small fix to multiple branches | Stash once, apply many times |
The Commands You’ll Actually Use
Saving a Stash
# Quickest — but gives you a useless name like "WIP on feature/login"
git stash
# Always do this instead — label it
git stash save "WIP: refactor auth middleware, step 2 of 4"
# New syntax (Git 2.13+), same result, supports more options
git stash push -m "WIP: refactor auth middleware, step 2 of 4"
# Stash untracked (new) files too
git stash -u
# Stash untracked AND ignored files (rarely needed)
git stash -a
# Stash only a specific file
git stash push -m "tweak: header padding only" src/components/Header.css
Real talk: I used to never add messages. After accumulating stash@{0} through stash@{7} with names like “WIP on main” and forgetting what any of them contained, I started treating stash messages the same as commit messages. Do it from day one.
Checking What You’ve Stashed
# See everything in the stash stack
git stash list
Sample output:
stash@{0}: On feature/checkout: WIP: cart total calculation, edge cases pending
stash@{1}: On main: hotfix: null check before payment gateway call
stash@{2}: On develop: WIP: API integration — auth token refresh not working yet
The index starts at {0} for the most recent stash. Once a stash is popped or dropped, everything shifts up.
# Quick summary: which files changed
git stash show
# Full diff — see exactly what's in there
git stash show -p
# Inspect a specific stash
git stash show -p stash@{2}
I run git stash show -p stash@{N} before restoring anything I haven’t touched in a few days. Context evaporates fast.
Restoring Stashed Work
# Pop: restore AND remove from the stash stack (most common)
git stash pop
# Apply: restore but LEAVE it in the stash stack (safer)
git stash apply
# Target a specific stash
git stash pop stash@{1}
git stash apply stash@{2}
My rule: if there’s any chance the restore might conflict, I use apply first. If everything merges cleanly and I’m satisfied, then I drop it manually. Losing a stash to an accidental pop with conflicts is painful.
Cleaning Up Stashes
# Drop one specific stash
git stash drop stash@{0}
# Drop EVERYTHING in the stash stack — no confirmation prompt
git stash clear
⚠️
git stash clearis irreversible. There’s nogit stash clear --undo. Once it’s gone, it’s gone.
Advanced Moves
Create a Branch Directly from a Stash
git stash branch feature/auth-refactor stash@{0}
This one command: 1. Creates a new branch off the commit where the stash was made 2. Checks it out 3. Applies the stash 4. Drops the stash if apply succeeded
I use this when I stashed changes days ago and the branch I stashed from has moved on significantly. Applying directly would be a conflict minefield — branching from the stash’s origin point sidesteps the problem entirely.
Stash Everything Except What’s Already Staged
git stash --keep-index
Useful when you’ve carefully staged a clean subset of changes and want to stash the rest (your WIP noise) before committing. This way you can commit just the staged chunk without the unfinished stuff cluttering your diff.
Interactive Partial Stash
git stash push -p
This drops you into an interactive hunk selector — the same interface as git add -p — so you can choose exactly which hunks to stash. Granular, but slow. Worth knowing when you need surgical precision.
Real Workflows From My Own Projects
Scenario 1: The Production Fire Drill
Classic. Deep in a feature, Slack goes red.
# Save exactly where I am
git stash save "WIP: checkout flow — promo code validation incomplete"
# Switch to main and branch off for the fix
git checkout main
git pull origin main
git checkout -b hotfix/payment-500-error
# ... diagnose, fix, commit, open PR ...
# After the hotfix is merged, return to the feature
git checkout feature/checkout-flow
git stash pop
The whole handoff takes under 30 seconds. No half-baked commits cluttering history, no lost work.
Scenario 2: Wrong Branch (It Happens to Everyone)
You’ve been coding for 45 minutes and realize you’re on main.
# Lock in the work
git stash save "oops: started new feature on main — moving to correct branch"
# Go where you should have been
git checkout -b feature/user-onboarding
# Bring the work over
git stash pop
Scenario 3: Pull Without the “Please Commit or Stash” Error
git stash save "WIP: pre-pull stash"
git pull origin main
git stash pop
# Resolve merge conflicts here if any
Note: if git stash pop after a pull creates conflicts, Git will flag them in the files as usual. The stash won’t be dropped (see troubleshooting below).
Scenario 4: Apply the Same Change to Multiple Branches
I recently fixed a misconfigured timeout value that needed to land on both develop and staging:
git stash save "fix: API timeout set to 10s (was 3s)"
# Apply to develop — use apply, not pop, so we keep the stash
git checkout develop
git stash apply
git add config/api.js
git commit -m "fix: API timeout set to 10s"
# Apply to staging — pop to clean up at the end
git checkout staging
git stash pop
git add config/api.js
git commit -m "fix: API timeout set to 10s"
Troubleshooting: What to Do When Things Go Sideways
Problem: git stash pop caused merge conflicts — now what?
When git stash pop hits conflicts, Git applies what it can and marks the conflicting hunks. The stash entry is NOT deleted — it stays in the stack until you explicitly drop it.
# 1. See what conflicted
git status
# 2. Resolve conflicts in each file (open in your editor)
# Look for <<<<<<< / ======= / >>>>>>> markers
# 3. Stage the resolved files
git add src/conflicted-file.js
# 4. Manually drop the stash (it wasn't auto-removed)
git stash drop
Do NOT run git stash pop again. The stash is still there — you’ll double-apply it.
Problem: Stashed changes disappeared after git stash clear
They’re gone. git stash clear has no undo.
Prevention: before clearing, always check what you’re deleting:
git stash list
git stash show -p stash@{0} # inspect before nuking
git stash clear
If you accidentally cleared and need to recover, it’s sometimes possible via git fsck:
git fsck --unreachable | grep commit | awk '{print $3}' | xargs git log --merges --no-walk
This surfaces dangling commits that might include your stash objects. Not guaranteed to work, especially after garbage collection. Don’t rely on this — just be careful with clear.
Problem: New files aren’t included in the stash
By default, git stash ignores untracked files (new files not yet added with git add).
# Wrong — new files won't be stashed
git stash
# Right — includes untracked files
git stash -u
I got burned by this when I stashed a branch with several new components, switched contexts, came back, ran git stash pop, and was confused why my new files were gone. They were never stashed. Always use -u when you have new files.
Problem: git stash pop restored changes to the wrong branch
Stashes are branch-agnostic — git stash pop applies to whatever branch you’re currently on. Git will warn you if the stash was created on a different branch, but it won’t stop you.
# Before popping, double-check your current branch
git branch --show-current
# Then pop
git stash pop
If you popped on the wrong branch, you can stash it again and move it.
Problem: Stash stack has grown out of control
git stash list
If you see more than 4–5 entries, it’s time to audit. For each one:
git stash show -p stash@{N}
Either apply and commit, or drop. Stashes are not a long-term storage solution — that’s what branches and commits are for.
Caveats and Limits to Know
- Stashes are local.
git pushdoesn’t push them.git clonedoesn’t copy them. They live only on the machine where they were created. - Stash vs. WIP commit: for longer-lived “saves,” consider a WIP commit on a personal branch instead. You can always
git reset HEAD~1to un-commit it later. WIP commits survive machine changes and collaborators pulling your branch. git stash clearis destructive and immediate. No confirmation. No undo (usually). Treat it likerm -rf.- Conflicts on pop are normal, not a bug. If your branch moved on since you stashed, expect conflicts. Plan for resolution time.
- Stash doesn’t save your Git index state perfectly. In some edge cases with
--keep-indexor partial stashes, what you get back might not be staged exactly as before. Alwaysgit statusafter restoring.
Quick Reference
| Command | What it does |
|---|---|
git stash save "msg" |
Save with a label |
git stash push -m "msg" <file> |
Stash a specific file |
git stash -u |
Include untracked files |
git stash list |
Show the full stash stack |
git stash show -p stash@{N} |
Full diff of a stash |
git stash pop |
Restore latest, delete from stack |
git stash apply stash@{N} |
Restore specific, keep in stack |
git stash drop stash@{N} |
Delete one stash |
git stash clear |
Delete ALL stashes (no undo) |
git stash branch <name> stash@{N} |
Create branch from stash |
git stash push -p |
Interactive partial stash |
git stash --keep-index |
Stash unstaged, keep staged |
Final Thoughts
git stash is one of those commands that slots quietly into your muscle memory and then one day saves your entire afternoon. The basics — save, pop, list — cover 90% of real-world situations. The advanced options — branch, --keep-index, -p — are there when you need surgical precision.
The two habits that made the biggest difference for me:
- Always write a message. Nameless stashes are a trap you set for your future self.
- Audit regularly. If your stash list is longer than 3 entries, something is being avoided, not solved. Commit it, branch it, or drop it.
If you’re interested in other Git workflows that save time on real projects — like interactive rebasing or bisect for hunting bugs — those are coming up next on Private Labs.
Related Guides on Private Labs
- How to Fix ‘Port Already in Use’ Errors in Node.js
- WSL2 Network Issues: What Caused Them and How I Fixed Them
- npm vs. mise: Which Task Runner Should Power Your Workflow?
More in Problem Solving.