In real projects, the “urgent hotfix” arrives exactly when you’re mid-feature with half-written code and tests open. You need a clean branch immediately, but you don’t want to toss your work or make a noisy WIP commit. That’s where git stash shines: it takes a snapshot of your working tree and (optionally) your staging area (index), parks it safely, and resets your tree to HEAD so you can switch context without risk.
Below I guide you through the exact flows I use on team projects: cleanly pausing work, jumping to hotfixes, restoring the exact state (including what was staged), moving a stash into its own branch, and a few creative tricks that make stash feel like a superpower. I’ll show the classic commands (as they appeared in my terminal) and note the modern equivalents that read better and help teammates.
Reference while you read: the official docs are excellent and precise — keep them open: git-scm.com/docs/git-stash.
A stash is a pair of snapshots:
By default, stash captures tracked files. Add -u/--include-untracked to include new, untracked files (and --all if you also want ignored files). Stashes live in a local stack: newest is stash@{0}, then stash@{1}, and so on. They’re local — not pushed to remotes — and that’s intentional.
Modern tip: git stash push -m "message" is the current, explicit form. Calling just git stash still works (and is equivalent to stash push), but I prefer push -m for clarity in teams.
Situation: On main, I’ve edited blog.html. Pager goes off. We need a hotfix.
What I did (classic):
git status
# shows modified: blog.html
git stash
# Saved working directory and index state WIP on main: <…>
git stash list
# stash@{0}: WIP on main: <…> (newest on top)
Why: Stashing gives me a clean working tree so I can branch for the hotfix without dragging along my WIP.
Modern equivalent:
git stash push -m "WIP: blog.html edits on main"
Now I branch, fix, and commit the hotfix:
Classic:
git checkout -b hotfix
git commit -am "hotfix: updated hello world - hello_world.py"
Modern:
git switch -c hotfix
# …fix…
git commit -am "hotfix: updated hello world - hello_world.py"
Back on main, I had a quick tweak to 404.html. I stashed it with a message (this matters once you have multiple stashes):
Classic:
git stash save "modified the title - 404.html"
git stash list
# stash@{0}: On main: modified the title - 404.html
# stash@{1}: WIP on main: <…>
Modern:
git stash push -m "modified the title - 404.html"
Team reality: When multiple engineers are hopping branches, labeled stashes act like a to-do stack you can understand at a glance.
Sometimes I need to inspect an older, unlabeled stash to see what it changes:
git stash show stash@{2}
# blog.html | 2 +-
# 1 file changed, 1 insertion(+), 1 deletion(-)
Add -p to view the patch:
git stash show -p stash@{2}
Why: I don’t want to apply/pop a random stash and create conflicts; I want the right one, first time.
You’ll hit this sooner than you think. I added a brand-new newfile.txt, then:
git stash
# No local changes to save
Because it’s untracked, plain stash ignored it. The fix:
Classic:
git stash -u
Modern:
git stash push -u -m "Include untracked: newfile.txt"
# or include ignored too:
git stash push --all -m "Include untracked+ignored"
Team scenario: Spikes, throwaway scripts, notes — they’re often untracked. If you want to park them, remember -u (or --all).
I typically apply when I might reuse the stash and pop when I’m done with it:
git stash apply # restore, but keep in the stack
git stash pop stash@{1} # restore and remove that entry if apply succeeds
git stash drop stash@{2} # remove a specific entry unconditionally
git stash clear # blow away all stashes (irreversible)
Conflict note: If apply/pop hits conflicts, Git leaves the stash in place. Resolve files, stage (git add), then drop or pop again as needed.
Team scenario: After a hotfix merges, I apply the relevant stash back on main, finalize the change, and drop the stash so the stack doesn’t grow stale.
This is the most common gotcha. Say I had newfile.txt staged and newfile2.txt unstaged, then I stashed. A plain apply brings everything back unstaged, which is not what I want when I’m composing clean, small commits.
Use --index to restore the index snapshot too:
git stash apply --index
# or
git stash pop --index
Why: A stash stores two trees (index + working). --index restores both. In team reviews, this helps you keep tight commit boundaries you planned before the interruption.
Sometimes I want to keep my staged changes ready for an immediate commit and hide only the other, noisy edits:
Classic:
git stash --keep-index
Modern:
git stash push --keep-index -m "Stash only unstaged; keep staged intact"
Team scenario: You’re splitting work into multiple logical commits; stash the unfinished hunks and ship the one that’s ready.
Bonus precision:
git stash push -- path/to/fileA dirB/ # stash only these paths
git stash push -p -m "Interactive patch stash" # pick specific hunks
git stash push --staged -m "Only staged changes to stash
Large stashes are harder to reason about and review. I convert them into a branch:
git stash branch demobranch # uses latest stash by default
# or explicitly:
git stash branch demobranch stash@{0}
This does four things for you:
From there, I commit normally, open a PR, run CI, get reviews — in short, I make the work first-class history instead of a blob hidden in my stash stack.
Team scenario: If apply keeps conflicting on main because the base moved, stash branch applies on the original base — far fewer conflicts.
You’ll see old docs (and muscle memory) using git checkout -- <path> to discard a file. The intent is clearer with:
git restore <path> # discard working changes to that file
git restore --staged <path> # unstage but keep edits
I’ve found teammates new to Git make fewer mistakes when we standardize on switch (for branches) and restore (for files).
Here’s a tidy day-in-the-life using modern forms:
# On main, mid-feature:
git status
git stash push -m "WIP: blog.html edits"
git switch -c hotfix
# ... fix, run tests ...
git commit -am "hotfix: correct 500 message"
git switch main
git stash push -m "WIP: 404 title tweak" # label each stash
# Include a new untracked scratch file
git stash push -u -m "Spike: newfile.txt"
# Later: restore EXACT staged/unstaged state
git stash apply --index
# Decide this belongs on its own branch:
git stash branch demobranch stash@{1}
# ... commit in small pieces, open PR, get review ...
This sequence plays nicely with CI, code review, and release trains — the things that truly matter on a team.
I avoid using stash as a long-term drawer. It’s local, easy to forget, and invisible to your teammates. If it’s important, promote it to a branch and make proper commits.
git stash isn’t just a panic button. Used deliberately — with messages, --index, --keep-index, -u, and stash branch — it keeps your flow intact and your team’s history clean. Keep the official documentation close (it covers advanced switches like --patch, --staged, export/import, and configuration toggles): Official docs: git-scm.com/docs/git-stash.
If you adopt the modern forms (stash push, switch, restore) and the habits above, you’ll move between urgent tasks and deep work without losing a minute — or a single carefully staged hunk.