Introduction to git stash
git stash is Git's built-in scratchpad. It takes the changes in your working directory and staging area, tucks them away on a private stack, and gives you back a clean working tree — as if you had just checked out the current commit. Later you can pop those changes back exactly where you left off. Think of it as a "pause button" for uncommitted work.
The 60-second mental model
What stash does to your three trees
Before stashing:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Working │ │ Staging │ │ Repository │
│ (dirty) │ │ (dirty) │ │ (HEAD) │
└──────────────┘ └──────────────┘ └──────────────┘
After git stash :
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Working │ │ Staging │ │ Repository │
│ (clean) │ │ (clean) │ │ (HEAD) │
└──────────────┘ └──────────────┘ └──────────────┘
▲
│
┌────────┴───────┐
│ Stash stack │
│ stash@{0} ◀── most recent
│ stash@{1}
│ stash@{2} │
└────────────────┘When to reach for stash
Urgent hotfix interrupts a feature. You are mid-feature, a P0 bug lands, and you need a clean branch right now.
Switching branches with dirty files. Git refuses to switch if a checkout would clobber local changes — stash, switch, come back.
Pulling on a dirty branch.
git pullon a dirty tree often fails; stash first, pull, pop.Mid-debug experiments. You added a bunch of
console.logcalls and want to test something else briefly without losing them.Quick demo or screenshot. You want HEAD as-is for a moment without committing WIP.
When NOT to use stash
Long-lived WIP. If you will not pop within a day or two, make a WIP branch and commit instead. Stashes are easy to forget about.
Work you need to share. Stashes are local-only. They never travel through
pushorfetch.Work that crosses machines. Same reason — stashes do not sync.
As a substitute for branches. Branches are cheap. Use them.
The two basic flows
Flow 1: stash and pop
# You are mid-edit on feature/login
git status
# modified: src/login.js
# modified: src/auth.js
git stash
# Saved working directory and index state WIP on feature/login: 3f2a1b9 Wire up form
git status
# nothing to commit, working tree clean
# ... do something else ...
git stash pop
# On branch feature/login
# Changes not staged for commit:
# modified: src/login.js
# modified: src/auth.js
# Dropped refs/stash@{0} (a1b2c3d...)Flow 2: stash, switch, and apply later
git stash push -m "WIP login form" git switch main git pull git switch - git stash pop
What gets stashed (and what doesn't)
Stashed by default: tracked files that are modified, and content currently in the staging area.
NOT stashed by default: untracked files (brand-new files Git has never seen).
NOT stashed by default: ignored files (anything matching
.gitignore).Use
-uto include untracked. Use-ato include ignored as well.
The stash stack
Stack visualisation
push pop
│ ▲
▼ │
┌─────────────────────────────────────┐
│ stash@{0} ← newest, popped first │
│ stash@{1} │
│ stash@{2} │
│ stash@{3} ← oldest │
└─────────────────────────────────────┘Stashes are local-only
A complete end-to-end example
Urgent hotfix while mid-feature
# 1. Mid-feature, dirty tree git status # modified: src/checkout.js # 2. P0 bug lands. Stash with a message. git stash push -m "WIP checkout total calculation" # 3. Hop to main, branch off, fix, commit, push, PR. git switch main git pull git switch -c hotfix/login-crash # ...edit... git commit -am "Fix null user in login flow" git push -u origin hotfix/login-crash # 4. Back to the feature git switch feature/checkout git stash pop # Picks up exactly where you left off
Useful commands at a glance
The stash subcommand family
git stash # stash tracked changes (shortcut for: git stash push)
git stash push -m "msg" # stash with a message
git stash list # show the stack
git stash show # summary of stash@{0}
git stash show -p # full diff of stash@{0}
git stash apply # restore stash@{0}, keep it on the stack
git stash pop # restore stash@{0}, then drop it
git stash drop # delete stash@{0}
git stash clear # delete ALL stashes (irreversible-ish)
git stash branch <name> # create a branch from stash@{0}