Git Stash and Stash Management: Save Work Without Committing
Master git stash for saving uncommitted changes, named stashes, stash list management, and when to use stash vs commit in production workflows.
Git Stash and Stash Management: Save Work Without Committing
When to Use / When Not to Use
Use Git Stash When
- Context switching — You need to switch branches but have uncommitted work
- Emergency fixes — Production is broken and you’re in the middle of a feature
- Experimentation — You want to try something without committing to it
- Pull rebase — You need a clean working directory for
git pull --rebase - Code review switches — You need to check out a PR branch while working on something else
Do Not Use Git Stash When
- Long-term storage — Stash is not a backup. Use branches for work you want to keep
- Sharing work — Stash is local-only. Push branches to share with teammates
- Completed features — If the work is done, commit it. Don’t stash finished code
- Large changesets — Stashing hundreds of files is a sign you should commit more frequently
Core Concepts
Git stash operates as a stack of saved changesets:
| Command | Description | Effect |
|---|---|---|
git stash | Save current changes | Working directory becomes clean |
git stash list | Show all stashes | Displays stash stack |
git stash pop | Apply and remove top stash | Restores changes, removes from stack |
git stash apply | Apply without removing | Restores changes, keeps on stack |
git stash drop | Remove a stash | Deletes from stack |
git stash clear | Remove all stashes | Empties the entire stack |
Each stash is a commit-like object that stores both the working directory and the index state.
graph LR
A[Working Directory] -->|git stash| B["stash@{0}"]
B -->|git stash| C["stash@{1}"]
C -->|git stash| D["stash@{2}"]
D -->|git stash pop| E[Working Directory]
Architecture and Flow Diagram
The complete stash lifecycle from creation through application or cleanup:
graph TD
A[Uncommitted Changes] -->|git stash| B[Stash Stack]
B -->|git stash list| C[View Stash List]
C -->|Decision| D{What to do?}
D -->|Restore + Remove| E[git stash pop]
D -->|Restore + Keep| F[git stash apply]
D -->|Delete One| G[git stash drop]
D -->|Delete All| H[git stash clear]
E --> I[Clean Working Directory]
F --> I
G --> B
H --> J[Empty Stack]
Step-by-Step Guide
1. Basic Stash Usage
The simplest form saves everything and cleans your working directory:
# Save all changes (staged and unstaged)
git stash
# Working directory is now clean
git status
# On branch feature/login
# nothing to commit, working tree clean
# Switch branches
git checkout main
# Do your emergency fix...
git commit -m "fix: resolve production issue"
# Return to your feature branch
git checkout feature/login
# Restore your stashed changes
git stash pop
2. Named Stashes
Give your stashes meaningful names so you can find them later:
# Stash with a message
git stash push -m "WIP: user authentication flow - 60% complete"
# Stash with a descriptive name
git stash push -m "feat: add password validation"
# List stashes with messages
git stash list
# stash@{0}: On feature/login: WIP: user authentication flow - 60% complete
# stash@{1}: On feature/login: feat: add password validation
# stash@{2}: On main: WIP: debug production memory leak
3. Selective Stashing
Stash only specific files or use the --keep-index flag:
# Stash only unstaged changes (keep staged changes)
git stash --keep-index
# Stash including untracked files
git stash --include-untracked
# or
git stash -u
# Stash including ignored files
git stash --all
# or
git stash -a
# Stash specific files (Git 2.13+)
git stash push -m "partial stash" -- src/auth.ts src/utils.ts
4. Managing the Stash List
Keep your stash list organized and clean:
# View all stashes
git stash list
# Apply a specific stash (by index)
git stash apply stash@{2}
# Pop a specific stash
git stash pop stash@{1}
# Drop a specific stash
git stash drop stash@{0}
# Show what's in a stash without applying
git stash show stash@{1}
# Or with full diff
git stash show -p stash@{1}
# Clear all stashes
git stash clear
5. Creating Branches from Stashes
Turn a stash into a proper branch:
# Create a branch from the latest stash
git stash branch feature/auth-from-stash
# Create a branch from a specific stash
git stash branch feature/password-validation stash@{2}
# This creates the branch, checks it out, and applies the stash
# The stash is automatically dropped after successful application
Production Failure Scenarios
| Scenario | What Happens | Mitigation |
|---|---|---|
| Stash conflict on pop | The codebase changed since stashing, causing conflicts | Resolve conflicts like a merge conflict; use git stash show -p to review before popping |
| Stash loss | git stash clear or accidental drop removes work | Stash is stored as commits — use git reflog to recover lost stashes |
| Stash stack overflow | Dozens of unnamed stashes become unmanageable | Name every stash; review and clean stash list weekly |
| Stash on wrong branch | Stashed changes don’t apply cleanly to the target branch | Use git stash branch to create a new branch from the stash |
| Untracked files lost | git stash without -u doesn’t save untracked files | Always use git stash -u if you have new files |
| Stash as permanent storage | Work sits in stash for weeks | Stash is local and fragile; use branches for anything you want to keep |
Trade-off Analysis
| Aspect | Advantage | Disadvantage |
|---|---|---|
| Speed | Instant context switch without commit | Changes are not shared with team |
| Flexibility | Can apply to any branch | Conflicts if target branch diverged |
| Organization | Named stashes with messages | Stack can become cluttered over time |
| Safety — Changes are saved as commits | Recoverable via reflog if accidentally dropped | Not visible in normal git log |
| Local-only | No remote pollution | Work is lost if disk fails |
| Selective stashing | Stash only what you need | Complex syntax for partial stashes |
Implementation Snippets
Stash Alias Configuration
# Add to ~/.gitconfig
[alias]
st = status
sl = stash list
sp = stash pop
sa = stash apply
sd = stash drop
ss = stash show
sn = "!f() { git stash push -m \"$*\"; }; f"
sc = stash clear
sb = "!f() { git stash branch \"$1\" \"${2:-stash@{0}}\"; }; f"
Stash Review Script
#!/bin/bash
# scripts/review-stash.sh
# Review all stashes and decide what to keep
echo "=== Stash Review ==="
echo ""
git stash list | while IFS=: read -r ref message; do
echo "--- $ref ---"
echo "Message:$message"
echo "Files changed:"
git stash show --stat "$ref" 2>/dev/null
echo ""
echo "Apply this stash? (y/n/d for drop)"
read -r action
case $action in
y) git stash apply "$ref" ;;
d) git stash drop "$ref" ;;
*) echo "Skipped" ;;
esac
echo ""
done
Pre-switch Hook — Auto-Stash
#!/bin/bash
# scripts/auto-stash-switch.sh
# Automatically stash before switching branches
BRANCH=$1
if [ -z "$BRANCH" ]; then
echo "Usage: auto-stash-switch.sh <branch>"
exit 1
fi
# Check for uncommitted changes
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Uncommitted changes detected. Stashing..."
git stash push -m "Auto-stash before switching to $BRANCH"
git checkout "$BRANCH"
echo "Switched to $BRANCH. Changes stashed."
echo "Run 'git stash pop' when ready to restore."
else
git checkout "$BRANCH"
echo "Switched to $BRANCH (no changes to stash)."
fi
Stash Age Monitor
#!/bin/bash
# scripts/stash-age-check.sh
# Warn about stashes older than 7 days
MAX_AGE_DAYS=7
THRESHOLD=$(date -d "$MAX_AGE_DAYS days ago" +%s 2>/dev/null || date -v-"${MAX_AGE_DAYS}d" +%s)
echo "=== Stash Age Report ==="
echo ""
git stash list --format='%gd %gs' | while read -r ref message; do
# Get the commit date of the stash
STASH_DATE=$(git log -1 --format='%ct' "$ref" 2>/dev/null)
if [ -n "$STASH_DATE" ] && [ "$STASH_DATE" -lt "$THRESHOLD" ]; then
echo "WARNING: $ref is older than $MAX_AGE_DAYS days"
echo " Message: $message"
echo ""
fi
done
Observability Checklist
- Logs: Not typically applicable — stash is a local operation
- Metrics: Track stash frequency per developer (high frequency may indicate commit discipline issues)
- Alerts: Alert when stash count exceeds 10 per developer or stashes older than 7 days exist
- Dashboards: Display stash count, average stash age, and stash-to-branch conversion rate
- Code Review: Check for stashed work during code reviews — stashed code should be committed or discarded
Security and Compliance Notes
- Local-only: Stash data never leaves your machine — it’s stored in
.git/refs/stash - No audit trail: Stash operations are not visible in remote logs or PR history
- Compliance gap: For regulated environments, all code changes should be committed and reviewed — stash bypasses this
- Data sensitivity: Stashed changes may contain sensitive data (API keys, credentials) — never stash secrets
- Recovery: Lost stashes can be recovered via
git reflogwithin the reflog retention period
Common Pitfalls / Anti-Patterns
- The Stash Graveyard — Dozens of unnamed stashes accumulate over months. Name every stash and clean up weekly.
- Stash as Commit Substitute — Using stash instead of committing finished work loses history and prevents code review.
- Pop Without Checking — Popping a stash onto the wrong branch creates conflicts. Always verify your branch before popping.
- Ignoring Untracked Files —
git stashwithout-uleaves new files behind, causing confusion when you return. - Stash Sharing Myth — Stash is local-only. You cannot share stashes with teammates. Use branches for shared work.
- Conflict Resolution Failure — When stash pop conflicts, the stash is NOT removed. You must resolve conflicts and then
git stash drop. - Stashing Secrets — Stashed changes may contain hardcoded credentials. Always check what you’re stashing.
Quick Recap Checklist
- Use
git stashfor temporary context switching, not long-term storage - Name every stash with
git stash push -m "description" - Use
git stash -uto include untracked files - Review stash list regularly and clean up old stashes
- Use
git stash show -pto review contents before applying - Use
git stash branchto convert stashes to proper branches - Never stash secrets or sensitive data
- Resolve conflicts after
git stash popbefore dropping the stash - Keep stash count under 10 per developer
- Commit finished work instead of stashing it
Stash vs Commit vs Worktree
| Aspect | Stash | Commit | Worktree |
|---|---|---|---|
| Persistence | Local, fragile, expires | Permanent in history | Permanent, independent |
| Shareability | Cannot be shared | Pushed to remote | Each worktree is local |
| Recovery | Via reflog if dropped | Always recoverable | N/A — files are on disk |
| Use case | Quick context switch | Completed or checkpointed work | Parallel branch work |
| Disk overhead | Minimal (one object) | Minimal (one object) | Full working directory copy |
| Visibility | Hidden from git log | Visible in git log | Visible via git worktree list |
| Best for | Hours of work, local only | Anything worth keeping | Days of parallel development |
Stash Hygiene Checklist
- Name every stash —
git stash push -m "descriptive message" - Apply promptly — Don’t let stashes sit for more than a few days
- Review before applying —
git stash show -p stash@{n}to confirm contents - Drop after applying — Use
popinstead ofapplyunless you need to keep it - Weekly cleanup — Run
git stash listand drop anything older than a week - Convert old stashes — Use
git stash branch <name>for stashes you still need - Never stash secrets — Check for credentials before stashing
- Include untracked files — Use
-uflag when you have new files - Keep count under 10 — More than 10 stashes means you’re using stash wrong
- Document stash purpose — If you can’t explain why it’s stashed, drop it
Interview Questions
git stash pop and git stash apply?git stash pop applies the stash and removes it from the stash stack. If there are conflicts, the stash remains on the stack so you can retry after resolving.
git stash apply applies the stash without removing it from the stack. This is useful when you want to apply the same stash to multiple branches or keep it as a backup.
In practice, use pop for the common case and apply when you need to preserve the stash.
Stashes are stored as commits, so they appear in the reflog. To recover a lost stash:
- Run
git reflogto find the stash commit - Look for entries like
stash@{0}orWIP on branch - Note the commit SHA
- Run
git stash apply <sha>to restore it
This works as long as the reflog hasn't been pruned (default retention is 90 days).
Use a branch when the work is complete enough to commit, when you need to share it with teammates, or when you want it to appear in the project history. Branches are visible, shareable, and permanent.
Use a stash when you need a quick context switch, when the work is too incomplete to commit meaningfully, or when you're experimenting and aren't sure if the changes are worth keeping.
Rule of thumb: if you'd be upset losing the work, it belongs on a branch, not in a stash.
Yes, since Git 2.13, you can stash specific files:
git stash push -m "partial stash" -- src/auth.ts src/utils.ts
Alternatively, use --keep-index to stash only unstaged changes while keeping staged changes in the working directory. Or use git stash --patch (or git stash -p) to interactively select which hunks to stash, similar to git add -p.
git stash without any arguments?It saves both staged and unstaged changes to the stash stack and leaves your working directory clean. The index state is also preserved in the stash. Essentially it creates a stash@{0} entry containing:
- Unstaged changes from working directory
- Staged changes from index
- Current branch state reference
Untracked files are not included by default — use git stash -u to include them.
git stash --keep-index work and when would you use it?This flag stashes only the unstaged changes while leaving your staged changes intact in the index. Use it when:
- You've partially staged changes for a commit but need to switch contexts
- You want to review unstaged changes separately before committing
- You're debugging and need to test only the unstaged portion
The staged changes remain in the index and will NOT be stashed.
git stash -u and git stash --all?-u or --include-untracked adds untracked files to the stash but still ignores ignored files.
-a or --all stashes both untracked and ignored files. This is useful when you want a complete snapshot including build artifacts, dependency folders, and other ignored content.
Use -u for normal workflows; use -a only when you genuinely need to preserve ignored files.
git stash branch <name> do?It creates a new branch from the specified stash and immediately checks it out, applying the stashed changes there. If a stash ref is not provided, it uses stash@{0}.
The key advantage: conflicts are handled better because Git performs the operation as a merge rather than a direct apply. After successfully applying to the new branch, the stash is automatically dropped.
This is the safest way to convert a stash into persistent work on a proper branch.
Use git stash show stash@{n} for a summary (list of changed files), or git stash show -p stash@{n} for the full diff output. This lets you review exactly what the stash contains before deciding whether to apply, pop, or drop it.
You can also use git stash list to see all stashes with their messages, then target specific ones for inspection.
Stash is local-only and stored in .git/refs/stash, but the stash objects themselves are Git commit objects that can persist in the reflog for 90 days. If you stash files containing:
- API keys or tokens
- Database passwords
- Private key files (
.pem,.key) - Environment files (
.envwith real credentials)
These can be recovered from reflog even after you think you've cleaned up. In team environments, stashed secrets create a compliance gap since stash operations bypass code review and audit trails. Always check what you're stashing with git stash show -p first.
Every stash operation (push, pop, apply, drop) creates an entry in the stash reflog. This is separate from the regular commit reflog. The reflog tracks all changes to the stash reference over time, including dropped stashes.
Entries look like stash@{0} — stash@{1} — etc. Even after git stash drop, the stash commit still exists and can be found via git reflog --all | grep stash. You can then recover with git stash apply <sha>.
Reflog retention is typically 90 days by default but can be configured.
git stash pop during a merge conflict?When git stash pop encounters conflicts, Git leaves the stash on the stack — it does NOT auto-drop. You must:
- Resolve the merge conflicts manually
- Stage the resolved files with
git add - Run
git stash dropto clean up
Many developers mistakenly think the stash was auto-removed and never run drop, leaving the stash around indefinitely. Always check git stash list after a conflicted pop to confirm cleanup.
A stash captures the full index state alongside the working directory, unlike a commit which only stores what was staged. When you apply a stash, the index state is also restored by default. Use git stash show --include-untracked to see the full picture. Since a stash is essentially a special commit object (not a regular one), it doesn't appear in git log output — only in git stash list and reflog.
git stash clear?Avoid git stash clear unless you're certain all stashes are either applied or no longer needed. This command removes all stashes at once and, while each individual stash commit remains in reflog, the reflog entries for them expire over time (default 90 days but configurable). If you accidentally clear, you may be able to recover via reflog for a limited window, but this is not guaranteed. It's safer to drop individual stashes after confirming they're no longer needed.
git stash -p (patch mode) work?git stash -p or git stash --patch launches interactive mode where Git shows each hunk and asks whether to stash it. Similar to git add -p, you can choose:
- y — stage this hunk
- n — skip this hunk
- s — split into smaller hunks
- ? — help
This enables precise control over what gets stashed when you only want partial changes, making it useful for separating unrelated modifications in the same file.
Stash and git worktree solve different problems. Worktrees let you have multiple working directories on different branches simultaneously — useful for parallel development. Stash saves uncommitted work temporarily and cleans your working directory. You can actually combine them: stash work in one worktree, then use another worktree to pop and work on it while your original worktree remains clean. Neither replaces the other — worktrees are for extended parallel work, stashes for quick context switches.
Hundreds of files suggests the work has grown large enough that it should have been committed in stages. Frequent large stashes indicate:
- Committing too late rather than making incremental checkpoint commits
- Working on too many concerns in a single branch without intermediate saves
- Using stash as a substitute for proper code review checkpoints
Git's staging area allows very granular commits — you can commit part of a file with git add -p. A healthy workflow uses small, frequent commits that can be squashed or reorganized later rather than massive stashes that hide significant work.
Stash operates as a LIFO stack — stash@{0} is always the most recent. When you pop, you get the top. When you apply a specific stash by index, older stashes shift their indices accordingly. A deep stack (20+) becomes hard to track mentally. Best practices:
- Keep stack depth under 10
- Name every stash (
git stash push -m "...") so you can find them later - Convert old stashes to branches if the work is still relevant
Git itself doesn't limit stack depth, but there's no UI affordance for managing deeply nested anonymous stashes.
The stash is branch-agnostic — it doesn't "belong" to the branch you created it on. When you run git stash, Git captures the working directory state and index, creates a stash commit, then cleans the working directory. The stash now exists independently in the refs/stash namespace. You can check out any branch and pop the stash there. However, the stash was created from the files in the original branch state, so applying it to a different branch may cause conflicts if the target branch's files have diverged significantly.
Configure these in ~/.gitconfig to improve stash habits:
stash.showIncludeUntracked = true— always show untracked files in stash outputstash.confirmShow = true— prompt before showing stash contentsalias.sn = "!f() { git stash push -m \"$*\"; }; f"— force named stashes
On the team level, consider a policy that stashes older than 48 hours must be either applied or dropped, and add pre-commit hooks that warn if you have uncommitted changes sitting for more than a day. Track stash metrics in CI to identify developers who may need commit discipline coaching.
Further Reading
- Git stash documentation — Official Git documentation
- Git reflog for recovery — Recovering lost stashes
- Git book: Stashing and Cleaning — Comprehensive guide
- Interactive stash with -p — Patch mode for selective stashing
- Git aliases for productivity — Speed up your workflow
Conclusion
Stash is the safety net for interrupted work — it lets you save half-finished changes without committing half-baked code. Master named stashes and the drop/pop distinction to avoid losing work in the cracks.
Category
Related Posts
Git Worktree for Parallel Work: Multiple Branches Simultaneously
Master git worktree to work on multiple branches simultaneously without stashing or cloning. Learn parallel development workflows, management commands, and best practices.
Master git add: Selective Staging, Patch Mode, and Staging Strategies
Master git add including selective staging, interactive mode, patch mode, and staging strategies for clean atomic commits in version control.
Git Aliases and Custom Commands: Productivity Through Automation
Create powerful Git aliases, custom scripts, and command extensions. Learn git extras, shell function integration, and team-wide alias standardization for faster workflows.