Git Stash
Work-in-progress management: save, retrieve, and manage uncommitted changes.
Stash Fundamentals
# BASIC STASH
git stash # Stash tracked changes
git stash push # Same, explicit
git stash -m "WIP: feature work" # Stash with message
# STASH OPTIONS
git stash -u # Include untracked files
git stash --include-untracked # Same, verbose
git stash -a # Include ignored files too
git stash --all # Same, verbose
git stash -k # Keep staged changes
git stash --keep-index # Same, verbose
# STASH SPECIFIC FILES
git stash push -- path/to/file.txt # Stash specific file
git stash push -- '*.adoc' # Stash by pattern
git stash push -m "WIP" -- dir/ # Stash directory with message
# INTERACTIVE STASH
git stash push -p # Patch mode (hunk by hunk)
# y = stash this hunk
# n = skip this hunk
# s = split hunk
# q = quit (stash selected)
# WHAT GETS STASHED
# - Modified tracked files
# - Staged changes (merged with modifications)
# NOT stashed by default:
# - Untracked files (use -u)
# - Ignored files (use -a)
# - Index/staging (staged and unstaged merged)
Retrieving Stashes
# APPLY STASH
git stash pop # Apply most recent + remove from list
git stash apply # Apply most recent, keep in list
git stash apply stash@{2} # Apply specific stash
# POP VS APPLY
# pop = apply + drop (removes stash)
# apply = just apply (keeps stash)
# USE pop for: one-time retrieval
# USE apply for: applying same stash to multiple branches
# APPLY PRESERVING INDEX
git stash apply --index # Restore staged/unstaged separately
# Default: all changes become unstaged
# --index: staged changes stay staged
# CREATE BRANCH FROM STASH
git stash branch new-branch # Create branch, apply stash, drop
git stash branch feature stash@{1} # From specific stash
# PARTIAL RESTORE (via patch)
git stash show -p stash@{0} | git apply # Apply as patch (can edit)
# DROP STASH
git stash drop # Remove most recent
git stash drop stash@{2} # Remove specific
git stash clear # Remove ALL stashes (careful!)
Inspecting Stashes
# LIST STASHES
git stash list # All stashes
git stash list --oneline # Compact format
# STASH LIST OUTPUT
# stash@{0}: WIP on main: abc1234 Last commit message
# stash@{1}: On feature: def5678 Another commit
# stash@{2}: WIP on main: abc1234 Last commit message
# SHOW STASH CONTENT
git stash show # Stat summary (default)
git stash show -p # Full diff (patch)
git stash show stash@{1} # Specific stash
git stash show -p stash@{2} # Specific stash with diff
# SHOW UNTRACKED FILES IN STASH
git stash show --include-untracked -p stash@{0}
git stash show -u -p # Short form
# STASH DETAILS WITH LOG
git log --oneline -1 stash@{0} # Stash commit info
git log -g stash # All stash entries with dates
# COUNT STASHES
git stash list | wc -l
# SEARCH STASHES
git stash list | grep "WIP" # Find by message
for i in $(seq 0 $(($(git stash list | wc -l) - 1))); do
echo "=== stash@{$i} ==="
git stash show -p stash@{$i} | head -20
done
Stash Workflows
# CONTEXT SWITCH WORKFLOW
# Working on feature, need to fix urgent bug:
git stash -m "WIP: feature/oauth halfway done"
git checkout main
git checkout -b hotfix/critical
# ... fix bug ...
git add -A && git commit -m "fix: critical bug"
git checkout main && git merge hotfix/critical
git push origin main
git checkout feature/oauth
git stash pop # Resume work
# CLEAN PULL WORKFLOW
# Have local changes, need to pull:
git stash
git pull origin main
git stash pop
# If conflicts: resolve, then git stash drop
# MOVE CHANGES TO NEW BRANCH
# Started work on main, should be on feature:
git stash
git checkout -b feature/new-work
git stash pop
# TEST ON CLEAN STATE
# Want to test without current changes:
git stash
# ... run tests on clean state ...
git stash pop # Restore changes
# SELECTIVE STASH WORKFLOW
# Only stash specific files:
git stash push -m "WIP: auth changes" -- src/auth.py
# Continue working on other files
# Later:
git stash pop # Get auth.py back
# MULTIPLE STASH MANAGEMENT
# Tag stashes clearly:
git stash push -m "FEAT: oauth - login flow"
git stash push -m "FIX: race condition debug"
git stash push -m "TEMP: logging for troubleshooting"
# Find and apply specific:
git stash list | grep "oauth"
git stash apply stash@{2} # Apply the oauth one
# STASH FOR REBASE
# Can't rebase with dirty tree:
git stash
git fetch origin
git rebase origin/main
git stash pop
Infrastructure Repository Stash Patterns
# DOCUMENTATION WIP PATTERN
# Working on runbook, need to build/test another:
cd ~/atelier/_bibliotheca/domus-infra-ops
git stash -m "WIP: k3s-prometheus runbook incomplete"
# Test another repo's build
cd ~/atelier/_bibliotheca/domus-docs
make
# Resume
cd ~/atelier/_bibliotheca/domus-infra-ops
git stash pop
# MULTI-REPO STASH STATUS
for repo in domus-infra-ops domus-captures domus-ise-linux; do
count=$(git -C ~/atelier/_bibliotheca/$repo stash list 2>/dev/null | wc -l)
if [ "$count" -gt 0 ]; then
echo "$repo: $count stash(es)"
git -C ~/atelier/_bibliotheca/$repo stash list
fi
done
# STASH BEFORE SYNC
# When running domus-push or similar:
for repo in ~/atelier/_bibliotheca/domus-*/; do
if [ -n "$(git -C "$repo" status --porcelain)" ]; then
name=$(basename "$repo")
git -C "$repo" stash -m "auto-stash before sync"
echo "Stashed: $name"
fi
done
# RESTORE AFTER SYNC
for repo in ~/atelier/_bibliotheca/domus-*/; do
stash_count=$(git -C "$repo" stash list 2>/dev/null | wc -l)
if [ "$stash_count" -gt 0 ]; then
name=$(basename "$repo")
echo "=== $name has $stash_count stash(es) ==="
git -C "$repo" stash list --oneline
fi
done
# STASH FOR ANTORA BUILD TESTING
# Test clean build:
cd ~/atelier/_bibliotheca/domus-infra-ops
git stash -u # Include untracked
cd ~/atelier/_bibliotheca/domus-docs
make # Build with committed content only
# Check if issues from uncommitted changes:
cd ~/atelier/_bibliotheca/domus-infra-ops
git stash pop
# EMERGENCY STASH
# About to pull/rebase, forgot about changes:
git stash # Quick save
git pull --rebase origin main
git stash pop
Advanced Stash Techniques
# STASH UNTRACKED ONLY
# Stash new files without touching modified:
git stash push -u --keep-index
# Result: staged changes preserved, untracked stashed
# STASH WITH PATHSPEC
git stash push -m "just tests" -- tests/
git stash push -m "configs" -- '*.yml' '*.yaml'
# APPLY AS PATCH (for flexibility)
git stash show -p stash@{0} > /tmp/stash.patch
# Edit patch if needed
git apply /tmp/stash.patch
# CREATE STASH WITHOUT APPLYING
git stash create "WIP message" # Returns SHA, doesn't save
git stash store -m "manual stash" <sha> # Store the SHA as stash
# STASH ENTRY ANATOMY
# Stash is a merge commit with 3 parents:
# - Working tree state (stash@{0}^0)
# - HEAD at time of stash (stash@{0}^1)
# - Index state (stash@{0}^2)
# - Untracked files if -u (stash@{0}^3)
# VIEW STASH INTERNALS
git log --graph --oneline stash@{0}^1..stash@{0}
# DIFF BETWEEN STASHES
git diff stash@{0} stash@{1}
# APPLY SPECIFIC FILE FROM STASH
git checkout stash@{0} -- path/to/file
# Or:
git show stash@{0}:path/to/file > path/to/file
# STASH REFLOG
git reflog show stash # Stash history
# Useful if you accidentally dropped a stash recently
# (within gc expiry period)
# RECOVER DROPPED STASH (if recent)
git fsck --unreachable | grep commit | awk '{print $3}' | while read sha; do
if git log -1 --format=%s "$sha" 2>/dev/null | grep -q "WIP on\|On branch"; then
echo "Possible stash: $sha"
git log -1 "$sha"
fi
done
Stash Gotchas
# WRONG: Expecting untracked files to be stashed
git stash
# New files NOT stashed!
# CORRECT: Include untracked with -u
git stash -u
# Now new files are included
# WRONG: Stash with merge conflicts
git merge feature
# CONFLICT...
git stash
# Error: cannot stash with conflicts!
# CORRECT: Resolve or abort first
git merge --abort
# Then stash
# WRONG: Pop with conflicts, losing stash
git stash pop
# CONFLICT...
# Stash is REMOVED even though pop failed!
# CORRECT: Use apply for safety
git stash apply
# CONFLICT...
# Stash still exists! Fix conflicts, then:
git stash drop
# WRONG: Assuming stash preserves staged state
git add file.txt
git stash
git stash pop
git status
# file.txt is UNSTAGED now!
# CORRECT: Use --index to preserve staging
git stash --index
git stash pop --index
# Staged state preserved
# WRONG: Stashing on wrong branch
git checkout feature
git stash
git checkout main
git stash pop
# Changes applied to main, not feature!
# CORRECT: Create branch from stash
git stash branch feature-restored stash@{0}
# WRONG: Relying on stash for long-term storage
# Stashes are local and can be lost
# CORRECT: Commit WIP to branch for safety
git checkout -b wip/my-feature
git add -A && git commit -m "WIP: save progress"
# Can always reset if needed
# WRONG: Clearing stash without checking
git stash clear
# All stashes gone! No recovery!
# CORRECT: Review before clearing
git stash list
git stash show -p stash@{0}
# Then clear if sure:
git stash clear
Quick Reference
# BASIC STASH
git stash # Stash tracked changes
git stash -u # Include untracked
git stash -m "message" # With description
git stash push -- path/ # Specific files
# RETRIEVE
git stash pop # Apply + remove
git stash apply # Apply, keep stash
git stash apply stash@{2} # Specific stash
git stash apply --index # Preserve staged state
# INSPECT
git stash list # All stashes
git stash show # Summary
git stash show -p # Full diff
git stash show -p stash@{1} # Specific stash diff
# MANAGE
git stash drop # Remove latest
git stash drop stash@{2} # Remove specific
git stash clear # Remove all (careful!)
git stash branch feature stash@{0} # Create branch from stash
# WORKFLOW
git stash # Save WIP
git checkout other-branch
# ... do work ...
git checkout original-branch
git stash pop # Resume
# OPTIONS
-u, --include-untracked # Include new files
-a, --all # Include ignored too
-k, --keep-index # Don't stash staged
-p, --patch # Interactive selection
-m "message" # Descriptive message