Git stash a single file: park the file, not the tree
stash push with a pathspec parks exactly the named file, -p splits hunks, and restore --source stash@{0} lifts one file back out with the entry intact.
git stash push -m "why" -- <path> parks exactly the named file; every other dirty file never moves.
One file back out of any stash: git restore --source stash@{0} -- <path> — the entry stays.
Pathspec form ships since git 2.13 (May 2017); untracked files need -u.
THE SPLIT
Three dirty files, one must move. Watch the tree divide — one file to the stash, two never move:
BEFORE · git status --short
M app.conf ← must move
M notes.md
M main.py
AFTER
M notes.md ← never moved
M main.py ← never moved
stash@{0}: On main: app.conf prod tweak
app.conf is back at its committed state and sits in stash@{0} — the -m message earns its three seconds the moment git stash list has more than one entry; names like "WIP" age badly
THE PATHSPEC IS THE WHOLE TRICK
Plain git stash sweeps the whole working tree — every tracked modification goes in, everything returns to HEAD. Wrong shape when the dirty tree is mixed: one file ready to hand over, the rest genuinely unfinished. Two details worth knowing:
- The pathspec comes after
--. Everything after the double dash is paths, not flags — the same convention asgit checkout -- <path>, and not decorative: older git versions could misread a bare path. - Untracked files need
-u. A brand-new file has no tracked history to stash, so plainpushskips it.git stash push -u -- newfile.pyincludes it;-agoes further and sweeps ignored files too.
HALF A FILE: THE INTERACTIVE SPLIT
When the file itself is half-ready — three good hunks, one embarrassing one — git stash -p (or git stash push -p) walks each hunk and asks Stash this hunk [y,n,q,a,d,j,g,/,e,p,?]?. Answer y for hunks that belong in the stash, n for the ones that stay; the result is a stash containing only what you approved. The same hunk-by-hunk machinery powers git add -p, so the reflex transfers. The two granularities, side by side:
git stash push -- <path> | git stash -p | |
|---|---|---|
| Granularity | whole files | individual hunks |
| Speed | one command, scriptable | interactive, per-hunk |
| Repeatable in CI | yes (paths as arguments) | no — needs a human at the prompt |
| Best for | "this file, not the rest" | "this change, not that one" |
| Since | git 2.13 (May 2017) | long-available |
Rule of thumb from the docs' own model: pathspec when the boundary is the file, -p when the boundary is inside it.
ONE FILE BACK OUT
git stash pop restores stash@{0} and deletes the entry — the normal path, but pop is all-or-nothing per stash, and a conflict aborts the pop with the entry preserved. Two finer-grained options:
# 1. apply without dropping (safe re-run)
git stash apply stash@{0}
# 2. pull ONE file out of a stash, leave the entry intact
git restore --source stash@{0} -- app.conf
# pre-2.23 spelling of the same operation:
git checkout stash@{0} -- app.conf
verify: git stash list after the restore → stash@{0} still standing — only pop deletes the entry
WHEN THE STASH IS THE WRONG TOOL
The stash is a scratchpad, not a branch. Stashes live only on your machine, carry no message beyond the one line, and are famously easy to forget — git stash list archaeology is a genre. Work that must survive days, travel between machines, or carry a real commit message belongs on a branch: git switch -c wip-labels, commit, switch back. The stash is for the next few hours, not the next sprint.
end of the single file · nothing fetched · everything local