You're halfway through writing a checkout regression test. The file is messy, the test doesn't run yet, and you definitely don't want to commit it. Then a developer pings you: "Can you pull main and run the smoke tests against this hotfix?" You can't switch branches with those uncommitted changes — Git might warn, refuse, or worse, leak them onto the wrong branch. The clean answer is git stash: save your half-done work to a hidden shelf, get a clean working directory, do the urgent thing, and pop the work back exactly where you left it.
What stashing actually does
git stash takes every uncommitted change in your working directory and staging area, packages them into an entry on a hidden stack, and resets your working directory to a clean state matching the last commit. The changes aren't gone — they live in .git/stash until you ask for them back. Switching branches, pulling, merging, even checking out an old commit all become safe.
The two-line workflow
The bare-minimum sequence:
git stash
# ...do whatever urgent thing required a clean working tree...
git stash popRun git stash:
git stashSaved working directory and index state WIP on feature/checkout-tests: 4c48901 Add cart fixture
git status confirms a clean tree:
git statusOn branch feature/checkout-tests
nothing to commit, working tree clean
You can now git switch main, git pull, run anything you like. When you're back on the original branch:
git stash popOn branch feature/checkout-tests
Changes not staged for commit:
modified: cypress/e2e/checkout.spec.js
Dropped refs/stash@{0} (a8f2c91...)
Your half-finished test is back exactly as you left it. Pop removes the stash entry as it applies it; git stash apply applies but keeps the entry on the stack.
Naming a stash
The default message ("WIP on feature/...") is forgettable when you have several stashes. Add a description:
git stash push -m "WIP: search tests, debounce assertion incomplete"(git stash save "..." is the older syntax — it still works, but push -m is the modern form.)
Multiple stashes
You can stash multiple times. List them:
git stash liststash@{0}: On feature/checkout-tests: WIP: search tests, debounce assertion incomplete
stash@{1}: On feature/login-tests: WIP: invalid-password fixture
stash@{2}: On main: WIP: tweak cypress.config.js timeout
The newest stash is always stash@{0}. Apply a specific one:
git stash apply stash@{2}Or pop a specific one:
git stash pop stash@{1}Drop one without applying:
git stash drop stash@{0}Wipe the whole stack (irreversible — be sure):
git stash clearInspecting a stash without applying
Curious what's in a stash before deciding? git stash show and git stash show -p:
git stash show stash@{0} cypress/e2e/checkout.spec.js | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
Add -p for the full patch:
git stash show -p stash@{0}You see the diff exactly as it would land if you popped.
Stash vs commit — when to use which
Both park work somewhere safe; they're suited to different intentions:
- Stash = "I'll be back in five minutes." Useful for genuine interruptions where the work isn't worth a commit message. The stash stack is a personal scratchpad.
- Commit (with a
WIP:prefix) = "This is a meaningful checkpoint." If you're stopping for the day, switching computers, or pushing to a backup remote, commit.git commit -m "WIP: search tests — debounce assertion not yet passing"is a perfectly valid checkpoint that you can amend (Chapter 4, Lesson 4) or squash later.
A useful rule: stash for minutes, commit for hours. If the work has lived in a stash for more than a workday, turn it into a WIP: commit before something happens to your machine.
A real QA scenario
Mid-afternoon. You're three test cases into feature/checkout-tests. None of them pass yet — you're still building the page object. Your tech lead messages: "Hotfix going out in ten minutes — can you pull main and run smoke?"
git status # confirm dirty tree
git stash push -m "WIP: checkout cases, page object half-built"
git switch main
git pull
npx cypress run --spec "tests/smoke/**" # smoke suite
# ...all green, hotfix ships...
git switch feature/checkout-tests
git stash pop
git status # back where you wereTotal context cost: 30 seconds. No half-baked work merged anywhere it shouldn't be, no uncommitted edits lost.
The full stash flow
Step 1 of 6
Working with uncommitted changes
Mid-task on a feature branch — files edited but not committed.
Stashing untracked files
By default, git stash only stashes tracked files. Brand-new files (untracked) stay in the working directory. To include them:
git stash push -u -m "WIP: includes new fixture file"-u = include untracked. There's also -a (--all) which includes ignored files too — almost never what you want.
⚠️ Common mistakes
- Forgetting which branch a stash belongs to.
git stash listshows the branch each stash was created on, butgit stash popapplies to whatever branch you're currently on. Pop a checkout-tests stash on top of a login-tests branch and you may get a conflict-laden mess. Always confirm your branch (git status) before popping. - Treating stash as long-term storage. Stashes are stored in
.git/stash, which is local to your machine — they don't push, don't sync, don't survive arm -rfor a wiped laptop. Anything you'd cry about losing belongs in a commit, not a stash. - Not naming stashes. Three days later,
stash@{2}: WIP on feature/foo: 4c48901...tells you nothing about what's inside. Alwaysgit stash push -m "..."with a description so future-you can actually choose the right one.
🎯 Practice task
Run a full interruption-and-resume cycle. 15-20 minutes.
- In your
qa-sandboxrepo (or any practice repo), make at least one edit to a tracked file. Don't commit. Confirm withgit statusthat the file is modified. - Run
git stash push -m "WIP: my first stash". Rungit statusagain — confirm the working tree is clean. - Run
git stash list. Confirm your stash is there with its message. - Switch to another branch (or stay on the same one and pretend), do something — even just
ls— and switch back. - Run
git stash pop. Confirm the change is restored and the stash is gone fromgit stash list. - Multiple stashes: make two different edits, stashing each with a unique message:
WIP: change AandWIP: change B. Rungit stash list. Apply only the older one withgit stash apply stash@{1}. - Stretch: create a brand-new untracked file. Run
git stash push -m "no-u test"— confirmgit statusstill shows it (untracked files aren't stashed by default). Now rungit stash push -u -m "with -u"— confirm the file is gone. Pop and confirm it returns.
The next lesson moves from saving work to inspecting it: log, diff, and blame — the three commands that turn Git from a black box into a readable record.