git stash advanced: CI-Safe Stash Patterns for DevOps Engineers¶
git stash is more than a quick "shelve my changes" shortcut. When you're juggling CI pipelines, hotfix branches, and feature branches simultaneously, the right stash pattern prevents lost work and merge noise.
Quick Reference Cheat Sheet¶
| Action | Command | When to Use |
|---|---|---|
| Save all changes | git stash |
Switch branches or pause for CI run |
| Save changes, keep index | git stash --keep-index |
When you want git stash pop to restore the staged state |
| Save changes for specific paths | git stash push -- <path1> <path2> |
Only stash modified files; leave README.md alone |
| List all stashes | git stash list |
See what's been saved across sessions |
| Show a stash's diff | git stash show -p stash@{2} |
Preview what a stash contains |
| Drop a stash | git stash drop stash@{1} |
Remove an unwanted stash |
| Drop all stashes | git stash clear |
Clean the slate entirely |
| Apply without removing | git stash apply |
Re-apply the same stash from multiple branches |
| Create branch from stash | git stash branch <new-branch> |
Turn a stashed change set into its own branch |
| Stash only tracked files | git stash --patch / git stash -p |
Interactively choose hunks |
| Stash untracked files | git stash -u or git stash -a |
Include new, untracked files |
stash pop vs stash apply: Why It Matters¶
git stash pop=git stash apply+git dropthe stash entry. Once popped, it's gone.git stash apply= re-apply the stash without removing it. Use when you want to:- Apply the same stash to two different branches
- Re-apply after a
popfailed part-way through
Pro tip: If
stash popleaves conflict markers, rungit stash applyinstead to keep the stash available while you resolve.
Stashing Specific Paths (Selective Stash)¶
# Stash only changes to src/components/Button.js
git stash push -- src/components/Button.js
# Stash everything *except* config files
git stash push -- '--' ':!(*)config*'
# Interactively choose hunks
git stash -p
CI Pattern: When a CI job starts pulling in new dependencies or changing lockfiles, selectively stash only the files you're actively working on, leaving package-lock.json or poetry.lock untouched.
git stash branch: Turning a Stash into a Branch¶
# Create a new branch from the current state, apply the stash, and drop the stash
git stash branch hotfix-stash main
This checks out main, applies the stashed changes there, and drops the stash. Ideal when you stash work on feature-A but need to pivot to a production hotfix immediately.
CI-Safe Stash Workflow Pattern¶
# 1. Before switching to a branch for a quick test
git stash -- "src/*.js"
# 2. Run the CI check on the clean branch
./ci-run-tests.sh
# 3. Re-apply the stash after CI completes
git stash pop
If the pop conflicts, fall back to:
Common Pitfalls & Fixes¶
| Problem | Fix |
|---|---|
stash pop fails with "untracked files would be overwritten" |
Use git stash apply first, then git stash drop; or git clean -fd before popping |
| "You cannot stash untracked files without -u/-a" | Always use git stash -u when you have new files you want preserved |
| Accidentally stashed changes you needed | git stash list → find the ref → git stash drop stash@{N} or git stash apply stash@{N} |
Losing staged changes after stash pop |
Use git stash --keep-index on stash, or git reset --staged after popping |
Recipe: Preserve the Index on stash pop¶
# Stash with index marker so `pop` restores staging state
git stash --keep-index
# ... switch branches, run CI, etc.
# Pop restores both the working tree changes AND the staging area
git stash pop
This is invaluable when your CI pipeline expects certain files to be committed (e.g., npm install producing package-lock.json that should be staged) but you need to switch contexts temporarily.
Advanced: Stash Management Script¶
A helper script (scripts/stash-manage.sh) is provided to:
- List stashes with file counts
- Apply a specific stash by index
- Drop all stashes older than N days
- Export/import stash to file for long-term preservation in CI environments