Stashing - Temporary Work Preservation
Architectural Context: The Stash Stack
Git’s stash mechanism provides a temporary storage system for uncommitted changes, enabling context switching without losing work-in-progress. Unlike commits, stashes exist outside the normal branch structure, functioning as a last-in-first-out (LIFO) stack for rapid state preservation and restoration.
Git’s Flexibility Principle
Git’s design embraces flexibility in how you manage work-in-progress. Just as Git allows selective staging of files or even parts of files, it doesn’t require you to commit everything at once—nor does it force you to lose uncommitted work when switching contexts. The stash mechanism exemplifies this philosophy: temporary storage without permanent commitment.
Design Insight: Stashing treats work-in-progress as legitimate repository state worth preserving, not as “incomplete work” to be discarded.
Conceptual Model
Problem Scenario: You’re mid-implementation when urgent production issues require immediate attention. Your working tree contains half-finished features and experimental code that shouldn’t be committed.
Traditional Workarounds (suboptimal):
- Commit incomplete work with “WIP” message (pollutes history)
- Copy files elsewhere (manual, error-prone)
- Use separate clones (disk space intensive)
Git’s Solution: Stash mechanism provides clean, reversible state preservation.
Basic Stash Operations
Stash Creation
# Stash all tracked file modifications
git stash
# Equivalent explicit form
git stash push
# Stash with descriptive message
git stash push -m "WIP: authentication refactor"Technical Behavior:
- Captures current working tree and staging area state
- Reverts working tree to HEAD state (clean working tree)
- Stores changes in stash stack with unique reference
- Enables immediate branch switching or pulling
Verification:
# Confirm clean state
git status
# Should show: "nothing to commit, working tree clean"Stash Inspection
# List all stashes
git stash list
# Output format:
# stash@{0}: WIP on main: abc1234 Last commit message
# stash@{1}: On feature: Authentication refactor
# stash@{2}: WIP on main: def5678 Previous workStash Reference Format: stash@{n} where n=0 is most recent, incrementing
for older stashes.
Detailed Stash Examination:
# Show changes in latest stash
git stash show
# Statistical summary
git stash show --stat
# Full diff
git stash show -p
git stash show -p stash@{1} # Specific stashStash Application
# Apply latest stash (keeps stash in stack)
git stash apply
# Apply specific stash
git stash apply stash@{2}
# Apply and remove from stack (pop)
git stash pop
# Pop specific stash
git stash pop stash@{1}Apply vs. Pop Decision Matrix:
- Use
apply: When you might need the stash again (experimental application) - Use
pop: When stash is single-use (standard workflow restoration)
Stash Removal
# Remove latest stash
git stash drop
# Remove specific stash
git stash drop stash@{2}
# Remove all stashes
git stash clearWarning: git stash clear is irreversible. Use with caution in repositories
with valuable experimental work.
💡 Useful Aliases
git config --global alias.save 'stash push -m'
git config --global alias.pop 'stash pop'Usage: git save "WIP: feature"
These aliases streamline your stash workflow with shorter, more memorable commands.
Advanced Stash Techniques
Selective Stashing
Problem: You have both production-ready changes and experimental modifications. You want to stash only the experiments.
Solution: Path-limited stashing
# Stash specific files
git stash push -m "Experimental logging" src/logger.py tests/logger_test.py
# Stash by pattern
git stash push -m "Debug artifacts" -- "*.log" "*.tmp"Use Case: Isolate debug instrumentation while preserving core changes for commit.
Interactive Stashing
# Interactively select changes to stash
git stash push -p
git stash push --patchInteractive Session:
diff --git a/src/auth.py b/src/auth.py
index abc1234..def5678 100644
--- a/src/auth.py
+++ b/src/auth.py
@@ -10,6 +10,8 @@ def authenticate(user):
if not user:
return None
+ # Debug logging
+ print(f"Authenticating: {user.email}")
Stash this hunk [y,n,q,a,d,e,?]?Commands: Same as git add -p (y=yes, n=no, s=split, e=edit)
Stashing Untracked Files
Default Behavior: Standard stash ignores untracked files.
# Include untracked files in stash
git stash push -u
git stash push --include-untracked
# Include even ignored files
git stash push -a
git stash push --allScenario: You created new files during exploration that aren’t yet tracked. Standard stash would leave them in working tree.
Stash with Keep-Index
Problem: You’ve carefully staged specific changes but need to stash unstaged modifications.
Solution:
# Stash unstaged changes, keep staged intact
git stash push --keep-indexWorkflow:
# Stage production-ready changes
git add feature.py
# Stash experimental changes
git stash push --keep-index
# Commit staged work
git commit -m "Add production feature"
# Restore experiments
git stash popStash Recovery and Conflict Resolution
Stash Application Conflicts
Scenario: Working directory has changed since stash creation, causing conflicts during application.
# Attempt stash application
git stash pop
# Conflict occurs
CONFLICT (content): Merge conflict in src/auth.py
The stash entry is kept in case you need it again.Resolution Process:
Step 1: Identify Conflicts
git status
# both modified: src/auth.pyStep 2: Resolve Conflicts
# Edit file, resolve conflict markers
vim src/auth.py
# Stage resolution
git add src/auth.pyStep 3: Stash Cleanup
# Manually remove applied stash
git stash dropNote: Unlike git stash pop, conflicts prevent automatic stash removal,
requiring explicit drop.
Stash to Branch Pattern
Use Case: Stashed work represents significant feature requiring dedicated branch.
# Create branch from stash state
git stash branch feature-stashed-work
# Or specify stash
git stash branch feature-x stash@{2}Technical Behavior:
- Creates new branch at commit where stash was created
- Checks out new branch
- Applies stash changes
- Removes stash from stack (if successful)
Advantage: Eliminates conflicts by applying stash to exact original commit state.
Stash Stack Management
Viewing Complete Stash State
# List with full context
git stash list --date=local
# Output:
# stash@{0}: WIP on main: abc1234 Refactor auth (Mon Jan 15 14:30:00 2024)
# stash@{1}: On feature: def5678 Add tests (Mon Jan 15 10:15:00 2024)Reordering and Cleanup
Scenario: Stash stack contains multiple entries; you need to reorganize.
Strategy: Apply specific stashes, then drop obsolete entries.
# Apply stash in different order
git stash apply stash@{3}
git commit -m "Incorporate earlier work"
# Remove obsolete stashes
git stash drop stash@{3}
git stash drop stash@{2}Automation Opportunity: Script stash cleanup for stashes older than N days.
Practical Workflow Patterns
Pattern 1: Emergency Context Switch
# Mid-feature, production issue arises
git stash push -m "WIP: user dashboard implementation"
# Switch to hotfix
git checkout main
git checkout -b hotfix/critical-auth-bug
# Fix, test, deploy
git commit -am "Fix authentication bypass"
git checkout main
git merge hotfix/critical-auth-bug
git push
# Resume feature work
git checkout feature-dashboard
git stash popPattern 2: Experimental Code Isolation
# Add debug logging throughout codebase
# (extensive modifications)
# Need to commit production changes
git stash push -u -m "Debug instrumentation"
# Stage only production-ready changes
git add src/feature.py
git commit -m "Implement feature X"
# Restore debug logging for continued investigation
git stash popPattern 3: Pull with Uncommitted Changes
# Local modifications present
git status
# modified: src/config.py
# Attempt pull
git pull
# error: Your local changes would be overwritten by merge
# Solution: Stash, pull, restore
git stash
git pull
git stash popAlternative: Rebase pattern
git stash
git pull --rebase
git stash popStash Limitations and Alternatives
When NOT to Use Stash
Stashing Reality Check: Stashing isn’t a substitute for proper branching strategy. If you find yourself:
- Creating dozens of stashes
- Losing track of what each stash contains
- Stashing work for days or weeks
…you probably need a branch instead. Stashing excels at temporary, short-term storage (minutes to hours), not long-term work management.
Rule of Thumb: If you can’t remember what’s in a stash without
git stash show, it’s been stashed too long.
What Stash Doesn’t Handle Well
❌ Long-term storage: Stash is temporary; use branches for work spanning days/weeks
❌ Shared state: Stash is local only; can’t share with teammates
❌ Complex experimental work: Multiple related experiments better managed as branches
❌ Partial file states: Stash operates on complete file changes, not line-level granularity
Alternative Patterns
For Long-Term WIP:
# Use WIP branch instead
git checkout -b wip/feature-exploration
git commit -m "WIP: Initial exploration"For Sharing Incomplete Work:
# Push WIP branch to remote
git push -u origin wip/shared-investigationFor Complex Experimentation:
# Use worktrees for parallel investigation
git worktree add ../experiment-a
git worktree add ../experiment-bPerformance and Safety Considerations
Stash Storage Characteristics
Storage Location: .git/refs/stash (reference log)
Performance: O(1) for push/pop operations regardless of stash stack size
Retention: Stashes persist until explicitly removed or repository deleted
Recovery: Stashed changes recoverable via reflog even after drop:
# Find dropped stash
git fsck --unreachable | grep commit
# Create branch from stash commit
git branch recovered-stash <commit-sha>Configuration and Customization
Stash Behavior Configuration
Configure how Git handles stashes for improved workflow:
# Show patch when stashing
git config --global stash.showPatch true
# Show stash statistics
git config --global stash.showStat true
# Include untracked files by default
git config --global stash.showIncludeUntracked trueEffect: When you run git stash, you’ll automatically see what’s being
stashed, making it easier to verify you’re stashing the right changes.
Stash Aliases
# Quick stash shortcuts
git config --global alias.save 'stash push -m'
git config --global alias.pop 'stash pop'
git config --global alias.peek 'stash show -p'
git config --global alias.list 'stash list'
# Stash with untracked files
git config --global alias.stash-all 'stash push --include-untracked -m'
# Usage
git save "WIP: feature implementation"
git stash-all "Complete workspace state"
git peek # Preview without applyingStash Display Customization
# Enhanced stash list format
git config --global alias.stashes "stash list --pretty=format:'%C(yellow)%gd%C(reset): %C(green)%s%C(reset) %C(blue)(%cr)%C(reset)'"
# Detailed stash information
git config --global alias.stash-info '!git stash show -p'Recommended Stash Configuration
Complete stash setup for optimal workflow:
# Core stash behavior
git config --global stash.showPatch false # Don't show patch on stash (can be verbose)
git config --global stash.showStat true # Show file statistics
# Helpful aliases
git config --global alias.stash-list "stash list --date=relative"
git config --global alias.stash-save 'stash push --include-untracked -m'
git config --global alias.stash-peek 'stash show -p'
# Verify configuration
git config --global --get-regexp stash
git config --global --get-regexp alias.stashCommon Pitfalls and Solutions
Pitfall 1: Forgetting About Stashes
Problem: Stash stack accumulates; context for each stash lost.
Solution: Always use descriptive messages
git stash push -m "Detailed description of stashed work"Maintenance: Regular stash list review and cleanup
# Weekly review
git stash list
# Remove obsolete stashes
git stash drop stash@{n}Pitfall 2: Stashing Without Message
# Creates generic "WIP on branch" message
git stash
# Better: Always include context
git stash push -m "Experimental query optimization"Pitfall 3: Losing Track of Stash Order
Problem: Multiple stashes create confusion about which is which.
Solution: Apply specific stash by number
# Review before applying
git stash show stash@{2}
# Apply specific stash
git stash apply stash@{2}Summary: Strategic Stash Application
Core Capabilities:
- Temporary Storage: Preserve work-in-progress without committing
- Context Switching: Enable rapid branch switching for urgent work
- Selective Preservation: Stash specific files or hunks
- Conflict Resolution: Handle stash application in changed contexts
Best Practices:
- Always include descriptive messages with
git stash push -m - Use
git stash applyfor experimental stash application - Regular stash list review and cleanup
- Prefer branches over stash for work spanning multiple days
Strategic Decision Framework:
- Use Stash: Quick context switches, temporary experiments, pulling with local changes
- Use Branches: Long-term WIP, shared work, complex feature exploration
Technical Excellence: Stash provides tactical flexibility for interrupt-driven development without polluting commit history or requiring manual file management.
Next Steps: Craft Meaningful Commits