You're mid-change on one thing when something more urgent lands — a hotfix, a branch switch,
a rebase you can't start with a dirty working tree — and none of your current edits are ready
to be a commit yet. git stash is the command for exactly that moment: it takes
your uncommitted changes, tracked and optionally untracked, and tucks them away on a stack
that lives outside any branch, leaving your working tree clean so you can switch context
immediately and come back later. Whether you typed "git and stash," "what does git stash do,"
or landed here mid-task already knowing the command but not the details, this guide covers all
of it: saving, naming, the git stash and pop round trip, restoring a single file, telling
apply apart from pop, and the part most tutorials skip entirely —
how to actually look inside a stash before you restore it. If what you actually want is to commit early and fix it up
afterward instead of stashing, that decision and the commands for it are covered in
the git undo last commit guide.
Quick Answer: What Git Stash Does in One Line
git stash saves your uncommitted changes to a hidden stack and resets your
working tree to match HEAD, so you get a clean slate without committing or
losing anything. Pick your exact scenario below — full explanations follow in the linked
sections.
| Situation | Command | Notes |
|---|---|---|
| Stash all tracked changes | git stash | Shorthand for git stash push |
| Stash with a descriptive message | git stash push -m "message" | Otherwise git auto-generates one from the branch and commit |
| Also stash untracked files | git stash push -u | Ignored files still excluded |
| Stash literally everything, ignored files too | git stash push -a | Rarely needed — usually means .gitignore is wrong |
| Stash a single file | git stash push -- path/to/file | Other modified files stay in the working tree |
| List every stash | git stash list | Newest is stash@{0} |
| Preview a stash before restoring | git stash show -p stash@{0} | Full diff, changes nothing |
| Restore and remove from the stack | git stash pop | Skips the removal step if a conflict occurs |
| Restore but keep it on the stack | git stash apply | Safer when you might need the same stash again |
| Delete one stash | git stash drop stash@{1} | Defaults to the newest entry if no index is given |
| Delete every stash | git stash clear | Irreversible through normal git commands |
The first two rows answer the most common phrasings of this question — "how to stash changes git" and "how to use git stash" — and for most sessions the whole thing is two commands typed hours apart:
# Something urgent came up — park the work in progress
git stash
# Back on it later — bring the changes right back
git stash pop Everything past that pair is about the parts that bite later: what a stash actually is, which files a plain stash leaves behind, how to look inside one before restoring it, and what happens when a pop hits a conflict.
What Does Git Stash Do? The Mental Model
The honest answer to "what does git stash do" and "how does git stash work" is that it wraps
your uncommitted changes into one or more real commit objects, then points a special
reference — refs/stash — at the newest one, chaining older entries behind it as
parents. That structure is a stack: last in, first out. stash@{0} is always
the most recent entry, stash@{1} the one before it, and so on. None of these
commits belong to any branch, which is exactly why git stash can leave your
working tree spotless — the changes still exist, just parked somewhere git log on
your branch will never show them.
Under the hood, a single stash entry is actually built from up to three commits: one capturing
your working-tree state, one capturing whatever was staged in the index at the time, and —
only if you stashed with -u or -a — a third capturing untracked
files. Git ties all of them together behind the one reference you interact with, so from the
command line a stash looks like a single unit even though internally it's a small commit
graph. That layout is the mechanical answer to how does git stash work at the object level,
and it's described in the same terms under the "Discussion" section of
git's official
git-stash documentation. As of Git 2.22, git stash itself was rewritten from
a shell script into a C builtin, which is why it's noticeably faster on large repositories
than it used to be — the behavior didn't change, just the implementation.
By default, a plain git stash grabs every tracked file with modifications —
both staged and unstaged changes, which answers "git stash unstaged" directly: unstaged edits
are included automatically, you don't need a special flag for them. There's no separate
git stash unstaged subcommand to hunt for — the default already takes both sides
of the index. What it leaves behind by
default is untracked and ignored files, covered in its own section below, since that's the
single most common surprise people run into the first time a stash "loses" a new file.
How to Stash Changes: git stash push
git stash push is the full command; bare git stash with no
subcommand is shorthand for it, and both do the same thing — this is the direct answer to
"how to stash changes git" and "how to use git stash." You'll also see
git stash save "message" in older tutorials: it's the predecessor command,
deprecated in favor of push since Git 2.13, and it's missing push's
pathspec support (no stashing just one file). Use push going forward;
save still works for backward compatibility but nothing here needs it.
$ git status
On branch main
Changes not staged for commit:
modified: src/api/client.ts
modified: src/api/retry.ts
$ git stash
Saved working directory and index state WIP on main: 4a1b2c3 add retry config
$ git status
On branch main
nothing to commit, working tree clean
A git stash example worth internalizing: after that git stash runs, both files
revert to exactly how they looked at your last commit, the changes aren't gone, they're saved
as stash@{0} and retrievable with apply or pop whenever
you're ready. One flag worth knowing early: --keep-index stashes everything as
usual but leaves your staged changes staged in the working tree afterward, useful when you
want a clean unstaged area but need to keep testing against what's currently in the index.
# Standard stash — working tree and index both reset to HEAD
git stash push
# Stash everything, but leave staged changes staged afterward too
git stash push --keep-index That's the whole of "how to use git stash" in the common case: one command to park the work, one to bring it back. Every git stash example past this point is a variation on scope — which files go in — or on what happens to the entry once you've restored it.
Naming Stashes and Reading git stash list
Without a message, git auto-generates one in the form
WIP on <branch>: <short-sha> <subject-of-HEAD>, which is fine for
one stash but gets confusing fast once you have three or four sitting around with nearly
identical auto-generated text. That's what the git stash with message form is for: pass
-m and the text is yours.
git stash push -m "wip: retry backoff before the auth hotfix" git stash list is how you read back what's saved, newest first, and it's the
answer to "git stash name" in the sense that matters most — the message you gave it (or the
auto-generated one) is exactly what shows up here:
$ git stash list
stash@{0}: On main: wip: retry backoff before the auth hotfix
stash@{1}: WIP on feature/csv-export: 9f8e7d6 add header row option
There's no command to rename a stash after the fact — a git stash name is set once, at
creation time, and git stash with message only works at the moment you create
the entry. If a name turns out to be wrong or unhelpful, the practical fix is to pop or apply
the stash, then re-stash it with -m and the message you actually wanted; there's no
in-place edit, unlike amending a regular commit's
message after the fact.
Stashing Untracked and Ignored Files: -u vs -a
By default, git stash only touches tracked files — anything git status
lists under "Untracked files" stays exactly where it is, untouched, when you run a plain stash.
This trips people up constantly: you stash, switch branches, and a brand-new file you were
working on is still sitting in your working tree, which can look like it "leaked" across the
stash boundary when really it was never included in the first place.
Two flags change that, and they cover different scope:
-
-u/--include-untracked— adds untracked files (new files git doesn't know about yet) into the stash, but still leaves anything matched by.gitignorealone. This is the answer to "git stash include untracked" and "git stash untracked" specifically. -
-a/--all— adds untracked and ignored files both. This is the wider net, and it's rarely what you actually want; reach for it only when you deliberately need to stash build artifacts or generated files alongside your real changes, since it's easy to accidentally sweep up things likenode_modulesor.envif your ignore rules are broad.
# Include new (untracked) files, skip anything gitignored
git stash push -u -m "wip: new csv parser module"
# Include everything, including ignored files — use sparingly
git stash push -a -m "wip: full snapshot before cleanup"
Both are per-command flags, not settings: the git stash untracked question comes down to
remembering -u at the moment you stash, because the default scope never widens
on its own. One further consequence worth knowing before it surprises you: when you later
pop or apply a stash created with git stash include
untracked semantics, the files that were untracked come back as untracked again —
stashing them doesn't retroactively start tracking them, it just preserves their content
across the round trip.
Stashing Certain Files Only
git stash push accepts a pathspec, which is the whole mechanism behind "git
stash certain files" instead of everything, and the direct fix for "git stash one file,"
"git stash single file," and "stash specific files git" — every version of the same question.
Put a double dash before the path(s) so git doesn't confuse a file name with a flag:
# Stash changes to one file only — everything else stays in the working tree
git stash push -- src/api/client.ts
# Stash a specific set of files
git stash push -- src/api/client.ts src/api/retry.ts
# Stash only what's currently staged (git 2.35+)
git stash push --staged --staged narrows scope the other direction: instead of picking files by path, it
stashes only whatever you've already git add-ed, leaving unstaged edits — even in
the same files — sitting in the working tree. For finer control than a whole file at a time,
-p (or --patch) walks through your changes hunk by hunk and lets you
choose y/n for each one interactively, the same review flow
git add -p uses for staging:
# Interactively choose which hunks to stash
git stash push -p
This combination — pathspec for whole files, --staged for the index only, and
-p for individual hunks — covers "git stash certain files" completely: pick the
granularity that matches how mixed your working tree actually is. Whichever way you phrased
it going in — git stash file, git stash one file, or git stash single file — the mechanism is
that one pathspec argument: git stash push -- <path>.
Inspect Before You Restore: git stash show and git diff
This is the step most tutorials skip, and it's the one that actually prevents mistakes: you can look at exactly what's inside a stash without touching your working tree at all, as many times as you want, before deciding whether to bring it back.
# Summary: which files changed, how many lines each
git stash show stash@{0}
# src/api/client.ts | 12 ++++++------
# src/api/retry.ts | 4 ++++
# 2 files changed, 10 insertions(+), 6 deletions(-)
# Full diff, every changed line, unified format
git stash show -p stash@{0}
# Compare the stash against your CURRENT working tree, not just its own parent
git diff stash@{0}
The distinction between those last two matters more than it looks: git stash show -p
shows the diff the stash recorded — the change relative to the commit you were on
when you stashed. git diff stash@{0} shows what would happen if you applied it
right now, against whatever your working tree looks like at this exact moment — which can
differ if you've made other commits or edits since stashing. If several stashes look nearly
identical in git stash list, running git stash show -p against each
one is the fastest way to tell them apart rather than guessing from the auto-generated message.
git stash show -p outputs a standard unified
diff, the same format git diff and plain diff -u produce.
For a longer or more tangled diff, reading it directly in the terminal gets hard fast. Copy
the output of git stash show -p stash@{1} into one pane of Diff Checker, a free
Chrome extension, and paste the current version of the same file into the other pane — its
Monaco-based editor lines the two up side by side (or as a unified view) and recomputes as you
edit either side, with no upload and no setup. That combination is exactly the "preview before
you commit to restoring" workflow: confirm what a git stash apply would actually
bring back before you run it, which matters most when a pop already conflicted once and you
need to compare the conflicted file against the stashed version to figure out what's still
different. For comparing whole files this way in general, see
the git diff between two files guide.
Restoring a Stash: git stash apply vs git stash pop
Both commands do the same restore; they differ only in what happens to the stack entry afterward, which is the entire answer to "git stash pop vs apply" and "how to unstash git."
-
git stash applyrestores the stash's changes into your working tree and keeps the entry on the stack. Use it when you might need the same stash again — applying it to a second branch, or as a safety net while you're not fully sure the restore is right. -
git stash poprestores the changes and then removes the entry — it'sapplyimmediately followed bydrop, and it's the more common choice once you're done with a stash for good. This literally is the "git stash and pop" and "restore git stash" workflow most people want by default.
# Restore the newest stash, keep it on the stack
git stash apply
# Restore the newest stash, remove it once restored cleanly
git stash pop
# Target a specific one instead of the default newest — stash@{0}
git stash apply stash@{2}
git stash pop stash@{2}
Neither command defaults to anything other than stash@{0} — the newest entry
— so "git stash apply specific stash," "git stash pop specific stash," and the bare "git
stash apply stash" phrasing all come down to the same thing: naming the index explicitly, as
shown above. One more flag worth knowing: plain apply or
pop only restores your working tree; add --index to also restore
which changes were staged versus unstaged at stash time, instead of dumping everything back
as unstaged modifications:
# Restore working tree AND staging state exactly as they were
git stash apply --index
The one-line rule for git stash pop vs apply: pop is apply plus
drop, so reach for apply whenever there's a chance you'll want a
second attempt at the same restore. Either command is a valid way to restore git stash
content into a working tree — the only difference is what's left on the stack when it's done.
Restoring a Single File From a Stash
Sometimes you don't want the whole stash back — just one file out of several that changed.
git checkout can pull a single path out of any commit-like reference, stashes
included, without touching anything else in your working tree:
# Restore just one file from a stash, leave everything else alone
git checkout stash@{0} -- src/api/retry.ts
# Modern equivalent (git 2.23+), same effect, clearer name
git restore --source=stash@{0} -- src/api/retry.ts
Both forms leave the stash entry untouched on the stack — this is a copy operation, not
apply or pop, so nothing is removed and the rest of the stash is
still there if you need another file from it later. It's the cleanest fix when a stash bundles
several files together but a full apply would create conflicts you don't want to
deal with for files you don't actually need restored right now.
Deleting Stashes: git stash drop and git stash clear
Two commands cover every version of "git stash delete," "git stash remove," and "git clear stash":
# Delete one specific stash entry
git stash drop stash@{1}
# Delete the newest entry (default target when no index is given)
git stash drop
# Delete EVERY stash entry at once
git stash clear drop removes exactly one entry and shifts the indices of everything below it up
by one, so re-check git stash list before dropping a second stash by index in the
same session. clear is the blunt instrument — it wipes the entire stack in one
command, with no per-entry confirmation, so it's worth running git stash list
first to make sure nothing on it is still needed. There is no git stash delete
and no git stash remove subcommand to go looking for — those two are the only
ones that exist, and "git clear stash" is just git stash clear with the words in
a different order. Neither command is reversible through normal git usage in the moment you
run it, though the next section covers the narrow recovery window that still exists right
after.
When git stash pop Hits a Conflict
This is the detail that catches people off guard: if the changes in a stash can't merge
cleanly into your current working tree — you've edited the same lines since stashing, or
switched to a branch with diverging content — git stash pop leaves conflict
markers in the affected files, exactly like a conflicted merge. Critically, the stash
entry is not dropped when that happens. Pop only removes the entry after a clean
restore; on conflict, the drop step is skipped entirely so your stashed work never disappears
into a half-merged file with no backup.
$ git stash pop
Auto-merging src/api/client.ts
CONFLICT (content): Merge conflict in src/api/client.ts
$ git stash list
stash@{0}: On main: wip: retry backoff before the auth hotfix Notice the stash is still listed after the conflict — that's the safety net. From here:
- Open the conflicted file(s) and resolve the markers, same as any merge conflict.
-
Stage the resolution with
git add <file>. There's nogit stash --continue; once files are resolved and staged, the pop is effectively done. -
Decide separately whether to run
git stash drop stash@{0}to clean up the now-redundant entry, or leave it a little longer as a fallback until you're confident the resolution is correct. - To bail out of the conflicted state entirely and try again later, discard the failed merge with a hard reset back to HEAD — the stash itself is untouched by this, since it was never dropped in the first place.
git stash branch and Recovering a Dropped Stash
git stash branch <new-branch-name> [stash] solves a specific version of the
conflict problem above pre-emptively: it creates a new branch starting from the commit that
was HEAD when the stash was made, checks that branch out, then pops the stash onto
it. Because the branch starts from the exact commit the stash was created against, the apply
step can't conflict due to divergence — it's the same starting point the stash already
expects. It's the same escape hatch the
Pro
Git "Stashing and Cleaning" chapter recommends when a stash refuses to reapply cleanly.
git stash branch fix/retry-backoff stash@{0}
This is the right tool specifically when your current branch has moved on since you stashed —
new commits landed, or you switched branches entirely — and a plain pop would
conflict for reasons that have nothing to do with the actual content, just a diverged base.
Once that branch has served its purpose, cleaning it up afterward is the same
local branch deletion workflow you'd use for
any short-lived branch. Note the boundary here: stashing moves uncommitted work
between branches, so if the change is already a commit sitting on the wrong branch,
copying that commit across
is a cherry-pick, not a stash.
Recovering a stash after drop or clear works because dropping a
stash doesn't destroy the underlying commit objects immediately — it only removes the
reference pointing at them. Until garbage collection actually runs, those commits are
"dangling" but still on disk, and git fsck can find them:
# List unreachable commit objects, including dropped stashes
git fsck --no-reflogs | grep commit
# Inspect a candidate to confirm it's the right one
git show <sha>
# Recover it — either re-apply directly or save it to a branch first
git stash apply <sha>
git branch recovered-stash <sha>
This only works before automatic garbage collection prunes unreachable objects — usually a
window of about two weeks by default, or sooner if something explicitly triggers
git gc. There's no guarantee past that point, which is the practical argument for
naming stashes clearly with -m and checking git stash list before
running clear, rather than relying on fsck as a routine safety net.
Viewing Stashes on GitHub (You Can't — Here's Why)
Directly: you cannot view a stash on GitHub, and there's no setting or workaround that changes
that. A stash lives entirely inside your local .git directory — as a
refs/stash reference and the commit objects it points to — and
git push has no mechanism that transmits it anywhere. It isn't a branch, isn't a
tag, and never gets included in a normal push, no matter what remote you're pushing to. GitHub,
GitLab, and Bitbucket all inherit this the same way: their web UIs have no concept of a "stash"
at all, because the underlying git protocol they read from never sees one — which is why a
"github view stash" search turns up no page, tab, or button anywhere in the interface.
If you actually need to hand stashed work to someone else or view it on another machine, two practical options replace "github view stash" as a goal:
-
Export it as a plain diff file —
git stash show -p stash@{0} > wip.patch— and share that file directly; anyone can apply it withgit apply wip.patch. -
Turn it into a real branch and push that instead —
git stash branch temp-wipfollowed bygit push -u origin temp-wip— which is genuinely visible on GitHub because it's an ordinary branch, not a stash anymore.
Git Stash Commands at a Glance
Five commands, side by side, so the choice between them is a lookup instead of a guess:
| Command | Effect on the stack | Effect on your working tree | Use when |
|---|---|---|---|
git stash apply | Entry stays on the stack | Restores the changes (add --index for staged state too) | You might need this stash again, or want a safety net |
git stash pop | Entry removed — only if the restore was clean | Restores the changes | You're done with the stash for good |
git stash drop | One entry removed | Unchanged | Discard a specific stash you don't need |
git stash clear | Every entry removed | Unchanged | Wipe the whole stack at once |
git stash branch <name> | Entry removed, if the pop onto the new branch succeeds | New branch created and checked out, then the stash is applied there | Your current branch has diverged since you stashed and a plain pop would conflict |
Frequently Asked Questions
How do I preview a stash's contents before applying it?
Run git stash show stash@{0} for a diffstat summary of which files changed,
or git stash show -p stash@{0} for the full unified diff of every line.
Neither command touches your working tree, so you can inspect a stash as many times as you
want before deciding to restore it. For the most complete picture when several
similar-looking stashes exist, git diff stash@{0} compares the stash
directly against your current working tree rather than against the commit it was created
from, showing exactly what would change if you applied it right now. Pasting that diff
alongside your current file into a side-by-side text comparison tool makes the difference
even easier to scan when the change is more than a few lines.
What is the difference between git stash pop and git stash apply?
git stash apply restores the stashed changes into your working tree but
leaves the stash entry sitting on the stack afterward, so you can apply the same stash
again elsewhere. git stash pop does the same restore and then deletes the
stash entry in one step — it's apply plus drop, and it's the more common choice once
you're confident you won't need that stash a second time. The one exception: if pop's
restore hits a merge conflict, the drop step is skipped and the stash entry survives on
the stack, so a failed pop never silently deletes your stashed work.
How do I apply a specific stash when I have several stashed at once?
Run git stash list first to see every entry with its index —
stash@{0} is the most recently created, stash@{1} the one
before that, and so on. Pass that reference explicitly to target it:
git stash apply stash@{2} or git stash pop stash@{2} restores
that specific entry regardless of where it sits in the stack, rather than defaulting to
the newest one. Indices shift as you drop or pop entries, so re-run
git stash list after any change before you reference an index again.
How do I stash just one file instead of everything?
Pass the file's path after a double dash: git stash push -- path/to/file.js
stashes only the changes to that file and leaves every other modification sitting in your
working tree untouched. List multiple paths to stash a specific set of files in one
command, or add -p (git stash push -p) to interactively choose
individual hunks within a file rather than the whole file at once. This is the direct
answer to stashing a single file or a handful of specific files without disturbing
unrelated work in progress.
What happens if git stash pop hits a conflict — is the stash removed?
No — this is the detail most guides skip. When the stashed changes can't merge cleanly
into your current working tree, git leaves conflict markers in the affected files and
stops, exactly like a conflicted merge, but it deliberately does not drop the stash entry.
That's intentional: dropping it would mean the only copy of your stashed work is stuck
half-merged into files you're still resolving. Resolve the conflicts, stage the results
with git add, and then decide separately whether to run
git stash drop to clean up the now-redundant entry, or leave it as a backup
until you're sure the resolution is correct.