Git Stashing: Save and Restore Work-in-Progress Without Losing Your Mind
Git stash saves and restores work-in-progress.
20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.
- ✓Basic Git commands (commit, branch, checkout)
- ✓Understanding of Git's three-tree architecture (working directory, index, HEAD)
Use git stash to save your dirty working directory, then git stash pop to restore it. For multiple stashes, use git stash list and git stash apply stash@{n}. Never stash untracked files by default — add -u to include them.
Imagine you're cooking a complex sauce and the fire alarm goes off. You don't throw the sauce away — you slide the pan off the burner, deal with the alarm, then put the pan back exactly where it was. Git stash is that side burner. It holds your half-finished work safely while you context-switch, then gives it back when you're ready.
Every developer has been there: you're deep in a refactor, half the files are a mess, and suddenly a production bug demands an immediate hotfix. Commit the half-baked work? That's a crime scene in your history. Delete it? You'll lose hours. The old hack was copying files to /tmp or creating WIP commits with messages like 'DO NOT DEPLOY'. Both are terrible. Git stash solves this cleanly — it shelves your changes without a commit, letting you switch branches freely. By the end of this article, you'll know exactly when to stash, when to commit, and how to avoid the three gotchas that have burned me in production.
Why Stash Exists: The Problem of Uncommitted Context Switches
Git is built around commits. But not every piece of work is ready to commit. Maybe you're in the middle of debugging with print statements everywhere. Maybe you've staged a partial fix but the full fix isn't done. Committing that mess pollutes your history and breaks git bisect. Before stash, teams used workarounds: temporary branches, manual file copies, or the dreaded 'WIP' commit. All of them add friction. Stash gives you a lightweight, stack-based way to save state without touching your commit history. It's not a replacement for branches — it's a temporary holding pen for when you need to context-switch fast.
git stash push -m "descriptive message" instead of plain git stash. When you have 10 stashes, 'WIP on main' is useless. 'WIP: partial auth refactor before hotfix' saves you minutes of inspection.Stash Stack: Managing Multiple Shelved Contexts
Stash is a stack (LIFO). Each stash is stored as stash@{n}. You can have multiple stashes active simultaneously — useful when you're juggling several half-finished features. But here's the trap: the stack grows fast, and without naming, you'll forget what each one contains. Always stash with a message. Use git stash list to see the stack. git stash show stash@{n} shows the files changed. git stash show -p stash@{n} shows the full diff. Never apply a stash blindly — inspect it first.
git stash pop on the wrong stash applies it AND drops it from the stack. If it conflicts, the stash is still dropped — you lose the original. Always use git stash apply first, then git stash drop after confirming a clean apply.Stashing Untracked and Ignored Files: The -u and -a Flags
By default, git stash only stashes tracked files (modified and staged). Untracked files (new files not yet added) are left behind. This is the #1 cause of 'lost' work after a stash. If you have new files you want to stash, use git stash -u (or --include-untracked). If you also want to stash ignored files (like .env or build artifacts), use git stash -a (or --all). Warning: -a can stash huge directories like node_modules — use with extreme caution. I've seen a stash balloon to 2GB because someone included -a in a monorepo.
git stash -a in a project with large ignored directories (node_modules, vendor, .next) will create a massive stash that takes forever to apply and may cause memory issues. Always use -u unless you explicitly need ignored files.Partial Stash: Stashing Only Specific Files or Hunks
Sometimes you don't want to stash everything. Maybe you have debug prints in one file and a real fix in another. git stash -p lets you interactively select hunks to stash, similar to git add -p. This is a lifesaver when you're deep in a debugging session and need to stash only the noise. Alternatively, you can stash a single file by using git stash push -m "msg" -- <file>. This stashes only the changes to that file, leaving everything else dirty.
git stash -p with git stash show -p to create a 'diff sandwich': stash partial work, review the stashed diff, then pop. This is great for splitting a messy working directory into clean logical stashes.Stash to Branch: Recovering from a Messy Stash
The most powerful stash command is git stash branch <branchname>. It creates a new branch from the commit where the stash was created, then applies the stash. This is the escape hatch when a stash won't apply cleanly to the current branch because the code has diverged too much. It's also the safest way to turn a stash into a proper branch for review. I use this constantly when I realize a stash should have been a feature branch all along.
git stash branch is the answer to 'How do you recover a stash that won't apply due to conflicts?' It creates a branch from the exact state when you stashed, avoiding the conflict entirely.When Not to Stash: The Case for Commits and Branches
Stash is a temporary tool. If your work will take more than a few hours, or if you need to collaborate on it, create a branch and commit. Stashes are local — they don't push to remotes. If your laptop dies, your stashes die with it. Also, stashes don't have a reflog (the stash itself is stored in .git/refs/stash but the individual entries are not in the reflog). Once dropped, recovery is painful. For work that's more than a quick context switch, use a feature branch with WIP commits that you'll squash later. Stash is for emergencies, not project management.
The Lost Hotfix That Cost a Weekend
git stash drop by accident. The fix was gone, and the team spent 6 hours rewriting it.git stash drop permanently deletes the stash entry. It does not create a commit or a reflog entry for the stash itself. The changes are only recoverable via git fsck if they haven't been garbage-collected.git fsck --lost-found and look for dangling blobs. Then git show <blob-hash> to inspect each one. Restore by redirecting to a file or applying with git stash apply on a reconstructed stash.- Never
git stash dropwithout first verifying the stash is safely committed elsewhere. - Use
git stash poponly when you're sure you want to remove it — otherwise usegit stash applyand drop manually later.
git stash pop failed with merge conflicts and stash is gonegit fsck --lost-found to find dangling blobs. 2. Inspect each blob with git show <hash>. 3. Manually reconstruct the changes or apply them with git stash apply on a reconstructed stash entry.git stash dropgit fsck --lost-found. 2. Look for dangling commits and blobs. 3. Use git show to inspect and redirect to files. 4. If too old, check if garbage collection has run — if so, recovery is impossible.git stash apply says 'No stash found'git stash list output carefully — maybe the stash was already dropped. 2. Run git reflog show stash (if available) or check .git/logs/refs/stash. 3. If not found, use git fsck as above.git fsck --lost-foundgit show <blob-hash>git stash apply on a reconstructed stash entry.| File | Command / Code | Purpose |
|---|---|---|
| stash-basics.sh | echo "debug statement" >> app.py | Why Stash Exists |
| stash-stack.sh | git stash push -m "WIP: refactor auth module" | Stash Stack |
| stash-untracked.sh | echo "new config" > new_config.yaml | Stashing Untracked and Ignored Files |
| partial-stash.sh | echo "debug1" >> app.py | Partial Stash |
| stash-to-branch.sh | git stash list | Stash to Branch |
| when-not-to-stash.sh | git stash push -m "big feature" | When Not to Stash |
Key takeaways
git stash apply instead of git stash pop to avoid losing the stash on conflict.-u; avoid -a in monorepos to prevent multi-GB stashes.git stash branch is the safest way to recover a stash that conflicts with the current branch.Interview Questions on This Topic
How does `git stash` handle staged vs unstaged changes internally? What happens to the index when you pop?
git stash creates two commits internally: one for the index (staged changes) and one for the working tree (unstaged changes). When you pop, it tries to restore both. If the working tree has diverged, the index restoration may fail. The stash is stored as a merge commit in .git/refs/stash.Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.
That's Git. Mark it forged?
3 min read · try the examples if you haven't