Home DevOps Git Stashing: Save and Restore Work-in-Progress Without Losing Your Mind
Intermediate 3 min · July 18, 2026

Git Stashing: Save and Restore Work-in-Progress Without Losing Your Mind

Git stash saves and restores work-in-progress.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Production
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
Before you start⏱ 25 min
  • Basic Git commands (commit, branch, checkout)
  • Understanding of Git's three-tree architecture (working directory, index, HEAD)
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer

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.

✦ Definition~90s read
What is Git Stashing?

Git stash temporarily shelves uncommitted changes (modified tracked files and staged changes) so you can work on something else, then reapply them later. It's a stack of unfinished work that lives outside your commit history.

Imagine you're cooking a complex sauce and the fire alarm goes off.
Plain-English First

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.

stash-basics.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// io.thecodeforge — DevOps tutorial

# Start with a dirty working directory
echo "debug statement" >> app.py
git add app.py
echo "another change" >> utils.py

# Save everything to stash
git stash
# Output: Saved working directory and index state WIP on main: abc1234 Last commit

# Working directory is now clean — switch branches safely
git checkout hotfix
# Do the hotfix, commit, push

# Return to original branch
git checkout main

# Restore the stashed changes
git stash pop
# Output: Dropped refs/stash@{0} (abc1234...)

# Now app.py and utils.py have your changes back
Output
Saved working directory and index state WIP on main: abc1234 Last commit
Switched to branch 'hotfix'
...
Switched back to branch 'main'
Dropped refs/stash@{0} (abc1234...)
🔥Senior Shortcut:
Use 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.

stash-stack.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// io.thecodeforge — DevOps tutorial

# Create multiple stashes with messages
git stash push -m "WIP: refactor auth module"
git stash push -m "WIP: fix payment bug"
git stash push -m "WIP: add logging"

# List all stashes
git stash list
# Output:
# stash@{0}: On main: WIP: add logging
# stash@{1}: On main: WIP: fix payment bug
# stash@{2}: On main: WIP: refactor auth module

# Inspect a specific stash
git stash show stash@{1}
# Output: payment.py | 10 +++++-----

# Apply without dropping (safe for inspection)
git stash apply stash@{1}
# Then verify, then drop manually
git stash drop stash@{1}
Output
stash@{0}: On main: WIP: add logging
stash@{1}: On main: WIP: fix payment bug
stash@{2}: On main: WIP: refactor auth module
payment.py | 10 +++++-----
⚠ Production Trap:
Running 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.

stash-untracked.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// io.thecodeforge — DevOps tutorial

# Create a new untracked file
echo "new config" > new_config.yaml

# Stash only tracked changes — new_config.yaml stays
git stash
# Output: Saved working directory and index state WIP on main: ...
# new_config.yaml is still present!

# Stash including untracked files
git stash -u
# Output: Saved working directory and index state WIP on main: ...
# new_config.yaml is now stashed

# To restore, same commands work
git stash pop

# For ignored files (e.g., .env)
git stash -a
# Warning: this stashes everything in .gitignore too
Output
Saved working directory and index state WIP on main: abc1234 Last commit
Saved working directory and index state WIP on main: abc1234 Last commit
⚠ Never Do This:
Running 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.

partial-stash.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// io.thecodeforge — DevOps tutorial

# Stash only changes in one file
echo "debug1" >> app.py
echo "real fix" >> payment.py

# Stash only payment.py
git stash push -m "partial: payment fix" -- payment.py
# app.py changes remain in working directory

# Interactive hunk selection
git stash -p
# Git shows each hunk and asks: (1/2) Stash this hunk [y,n,q,a,d,/,e,?]?
# Answer y for hunks you want to stash, n to leave

# After partial stash, remaining changes are still dirty
git status
# Shows app.py as modified
Output
Saved working directory and index state WIP on main: partial: payment fix
...
(interactive prompts)
On branch main
Changes not staged for commit:
modified: app.py
💡Senior Shortcut:
Combine 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.

stash-to-branch.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// io.thecodeforge — DevOps tutorial

# Suppose you have a stash that conflicts on current main
git stash list
# stash@{0}: On main: WIP: refactor auth

# Create a new branch from the stash's original commit
git stash branch refactor-auth stash@{0}
# Output: Switched to a new branch 'refactor-auth'
#         On branch refactor-auth
#         Changes not staged for commit:
#           modified:   auth.py
#         Dropped stash@{0} (abc1234...)

# Now you're on a clean branch with the changes applied
# No conflicts! Commit normally and push.
git add auth.py
git commit -m "refactor auth module"
Output
Switched to a new branch 'refactor-auth'
On branch refactor-auth
Changes not staged for commit:
modified: auth.py
Dropped stash@{0} (abc1234...)
🔥Interview Gold:
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.

when-not-to-stash.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — DevOps tutorial

# Bad: using stash for long-term work
git stash push -m "big feature"
# ... days later ...
git stash list  # still there, but risky

# Good: use a branch with WIP commits
git checkout -b feature/big-feature
git add .
git commit -m "WIP: partial feature"
# Push to remote for backup
git push origin feature/big-feature
# Later, squash before merging to main
⚠ The Classic Bug:
Stashes are not backed up. If your repository is cloned fresh, stashes are gone. I've seen a developer lose a week of work because they relied on stashes across a machine migration. Always commit and push long-lived work.
● Production incidentPOST-MORTEMseverity: high

The Lost Hotfix That Cost a Weekend

Symptom
A developer stashed a critical hotfix to switch branches, then ran git stash drop by accident. The fix was gone, and the team spent 6 hours rewriting it.
Assumption
The team assumed stash drop was reversible like a commit.
Root cause
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.
Fix
Immediately run 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.
Key lesson
  • Never git stash drop without first verifying the stash is safely committed elsewhere.
  • Use git stash pop only when you're sure you want to remove it — otherwise use git stash apply and drop manually later.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
git stash pop failed with merge conflicts and stash is gone
Fix
1. Run git 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.
Symptom · 02
Stashed changes are missing after git stash drop
Fix
1. Immediately run git 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.
Symptom · 03
Stash list shows entries but git stash apply says 'No stash found'
Fix
1. Check 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 Stash Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
`git stash pop` failed with `CONFLICT` and stash is gone
Immediate action
Stop. Do not run any other Git commands.
Commands
git fsck --lost-found
git show <blob-hash>
Fix now
Manually reconstruct changes or use git stash apply on a reconstructed stash entry.
Accidentally dropped the wrong stash+
Immediate action
Check if it's still in the list.
Commands
git stash list
git fsck --lost-found
Fix now
If not in list, recover from dangling blobs with git show and redirect to files.
Stash applied but files are missing (untracked not included)+
Immediate action
Check if files were untracked.
Commands
git stash show -p
git stash list
Fix now
If the stash didn't include untracked files, you need to recreate them. Check your editor's local history or undo with git checkout . if you haven't made other changes.
Stash is huge (multi-GB) and apply hangs+
Immediate action
Kill the command with Ctrl+C.
Commands
git stash drop
git stash list
Fix now
Never use -a in monorepos. Use -u instead. If you need the stash, apply with --index and be patient.
Featuregit stashgit commit (WIP branch)
Persistence across clonesNo — local onlyYes — pushed to remote
Recovery after dropDifficult (git fsck)Easy (reflog)
CollaborationNo — single userYes — push/pull
History pollutionNone — outside historyYes — but squashable
Best forQuick context switch (<1 hour)Long-lived work (>1 hour)
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
stash-basics.shecho "debug statement" >> app.pyWhy Stash Exists
stash-stack.shgit stash push -m "WIP: refactor auth module"Stash Stack
stash-untracked.shecho "new config" > new_config.yamlStashing Untracked and Ignored Files
partial-stash.shecho "debug1" >> app.pyPartial Stash
stash-to-branch.shgit stash listStash to Branch
when-not-to-stash.shgit stash push -m "big feature"When Not to Stash

Key takeaways

1
Stash is for quick context switches (<1 hour), not long-term work
use branches and commits for anything longer.
2
Always use git stash apply instead of git stash pop to avoid losing the stash on conflict.
3
Include untracked files with -u; avoid -a in monorepos to prevent multi-GB stashes.
4
git stash branch is the safest way to recover a stash that conflicts with the current branch.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does `git stash` handle staged vs unstaged changes internally? What ...
Q02SENIOR
When would you choose `git stash branch` over manually resolving conflic...
Q03SENIOR
What happens to a stash if you run `git gc`? Can you recover a dropped s...
Q04JUNIOR
What is the difference between `git stash` and `git stash save`?
Q05SENIOR
A developer stashed changes, then ran `git stash drop` by accident. How ...
Q06SENIOR
How would you design a workflow that uses stash for emergency hotfixes i...
Q01 of 06SENIOR

How does `git stash` handle staged vs unstaged changes internally? What happens to the index when you pop?

ANSWER
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.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
How do I recover a dropped stash in Git?
02
What's the difference between git stash pop and git stash apply?
03
How do I stash only specific files in Git?
04
Can I stash untracked files in Git?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Verified
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
🔥

That's Git. Mark it forged?

3 min read · try the examples if you haven't

Previous
Git Rebasing: Interactive Rebase and Best Practices
49 / 51 · Git
Next
Git Worktrees: Work on Multiple Branches Simultaneously