Devpuff
Pricing
Log InStart Free
  1. Home
  2. Blog
  3. git stash: park changes without committing
Tools

git stash: park changes without committing

Stash puts your uncommitted work aside and gives you a clean tree. It leaves untracked files behind unless you ask for them.

By Max Arthur
Co-Founder & Content Marketer·September 24, 2026·8 Min read
White text reading 'Git stash explained' on a dark purple dotted background

git stash takes your uncommitted changes, stores them somewhere safe, and gives you a clean working directory:

git stash          # park everything
git stash pop      # bring it back

It exists for the moment when you are halfway through something and need to be somewhere else: a bug on main, a colleague's branch to review, a pull that refuses to run because you have local changes.

There is one behaviour that costs people work, and it is the default: untracked files are not stashed. Everything here was measured on git 2.50.0.

The untracked file problem

Start with one modified file and one brand-new file:

 M a.txt
?? u.txt

Run git stash, then look again:

?? u.txt

a.txt was stashed and restored to its committed state. u.txt is still sitting there, untouched. Your working directory is not clean, and if you were stashing in order to switch branches cleanly, it is not clean.

This is by design: git will not take responsibility for files it has never tracked. It is still surprising, and the surprise is worst when a new file is the most important part of your work.

Ask for them explicitly:

git stash -u          # include untracked files
git stash -a          # include ignored files too

Measured with -u, u.txt disappears from the working directory and comes back with git stash pop. That is the flag to use by default. -a also sweeps up ignored files such as node_modules and build output, which is almost never what you want.

pop, apply, and the difference

git stash pop      # apply the stash and delete it
git stash apply    # apply the stash and KEEP it

Measured: after apply the stash list still had one entry; after drop it had none. pop is apply plus drop in one step.

Use apply when you want the same changes on two branches, or when you are not certain the stash will apply cleanly and want a second attempt. Use pop for the ordinary case.

One important detail: on a conflict, pop keeps the stash. Applying a stash onto a file that has changed since produced this:

UU a.txt

and the stash list still had one entry. That is deliberate. pop only deletes the stash once it has applied cleanly, so a conflict cannot lose your work. Resolve the conflict, then drop it yourself:

git stash drop

The stash is a stack

git stash list
stash@{0}: WIP on main: 955e9cf first
stash@{1}: WIP on main: 955e9cf first

New stashes go on top, so stash@{0} is the most recent and is what pop and apply use by default. Older ones keep their numbers only until something above them is removed, at which point everything shifts down, which is the main argument against leaving stashes lying around.

Work with a specific one by name:

git stash apply stash@{2}
git stash drop stash@{2}
git stash show -p stash@{1}    # see the actual diff

git stash show -p is worth knowing. The default WIP on main message tells you nothing about the contents, and after a week you will have no idea what a stash contains.

Give them names when you make them:

git stash push -m "half-finished login validation"

That message shows up in git stash list, and it turns the stash from a mystery box into something you can actually come back to.

Stashing part of your work

git stash push -p

Git walks through each hunk and asks whether to stash it. This is how you park an unrelated experiment while keeping the change you were actually working on.

You can also stash specific paths:

git stash push -m "just the css" -- styles/

Both are more precise than the all-or-nothing default, and both are worth reaching for when only part of your working directory is in the way.

Turning a stash into a branch

When a stash has outlived the branch it came from, this is the clean escape:

git stash branch new-feature

That creates a branch from the commit the stash was made on, applies the stash, and drops it. Because it starts from the original commit, it applies cleanly even when the current branch has moved on, which is exactly the case where pop would conflict.

If you find yourself resolving conflicts to pop an old stash, this is usually the command you wanted.

A worked example: the urgent bug

The situation stash was built for. You are halfway through a feature, with edits across several files and nothing worth committing, when a production bug needs fixing on main.

git stash -u -m "half-done search filters"
git switch main
git pull
git switch -c hotfix-search-crash
# fix it, commit, push, open the PR
git switch feature-branch
git stash pop

You are back exactly where you were, with the same files modified and the same untracked files present.

Two details make this work reliably. The -u takes untracked files with you, so the new branch really is clean. The -m names the stash, so if the hotfix takes two days you still know what stash@{0} contains when you come back.

Without the stash, the alternative is committing half-finished work, switching, and then remembering to uncommit it later. That works too, and is arguably safer for anything that will take more than an afternoon.

What a stash actually is

A stash is a commit, which explains most of its behaviour.

git stash creates commits recording your working directory and index, stores them under refs/stash, and resets you to HEAD. git stash list is reading a log of that ref, and stash@{0} is a reflog-style reference to its most recent entry.

That is why:

  • Applying can conflict. It is merging a commit into your current state, and merges conflict.
  • A dropped stash is recoverable. The commits survive until garbage collection, which is what makes the git fsck recovery below work.
  • git stash show -p produces a diff. It is diffing a commit against its parent, like any other commit.
  • Stashes are not pushed. refs/stash is not in the set of refs git shares with a remote.

Seeing it as "a commit on a hidden branch" makes the whole command predictable, and it is the reason the advice below is to use a real branch when the work matters.

What stash is not for

Long-term storage. A stash is a stack with no branch name, no description by default, and no presence on any remote. Work that matters belongs on a branch:

git switch -c wip-something
git add -A
git commit -m "WIP"

A throwaway commit on a branch is visible in git log, survives a clone, can be pushed, and can be reshaped later with an interactive rebase. A stash does none of that. The rule of thumb: if the work will still exist tomorrow, commit it.

Sharing. Stashes are strictly local. There is no git push for them.

Moving between repositories. Also no. A patch file does that job.

Recovering a dropped stash

Dropping a stash you wanted is recoverable, because the stash was a commit and the commit survives until garbage collection:

git fsck --unreachable | grep commit

That lists unreachable commits, and the stash is among them. Inspect the candidates with git show <hash> until you find yours, then:

git stash apply <hash>

It is more work than it should be, which is another argument for committing anything you would be upset to lose.

The alternative worth knowing

If you switch context often, there is a way to avoid stashing entirely:

git worktree add ../hotfix main

That checks out main into a second directory, sharing the same repository. You now have two working directories side by side, and switching between them is switching terminal tabs rather than moving your files around.

Your feature work stays exactly as it is, untouched, because nothing about your original directory changes. When the hotfix is done:

git worktree remove ../hotfix

It costs disk space and a little setup, and in exchange the whole stash-switch-pop dance disappears. For anyone who is interrupted regularly, it is the better tool, and it is one of the more useful git features that beginners never hear about.

Three common mistakes

Forgetting -u and then switching branches. The untracked files come with you, which is confusing at best and, if the new branch has a file with the same name, a genuine mess. Make -u your default and the problem disappears.

Stashing and forgetting. A stash with no message, three weeks old, sitting under two newer ones. You will not remember what it holds and git stash show -p will not tell you why you made it. Name them, or commit to a branch instead.

Popping onto the wrong branch. A stash carries no record of where it came from and applies wherever you are standing. It will happily apply your feature work onto main and often succeed. Check git status after popping, before you commit anything.

Quick reference

git stash                  # park tracked changes
git stash -u               # include untracked files
git stash push -m "note"   # name it
git stash push -p          # choose hunks
git stash list             # what is stashed
git stash show -p          # what is in the top stash
git stash pop              # apply and remove
git stash apply            # apply and keep
git stash drop             # remove without applying
git stash branch <name>    # turn a stash into a branch
git stash clear            # delete every stash

Want to practise the switching-context workflow safely? Work through Git basics in a real repository in the browser.

Keep reading

More from the blog

White text reading 'Objects are not valid as a React child' on a dark purple dotted background
October 7, 2026·7 min readTools

Objects are not valid as a React child: what to render

Objects are not valid as a React child, and React tells you which one by listing its keys. In React 19 the promise version throws a different error.

Read more
White text reading 'How to fix npm install errors' on a dark purple dotted background
October 6, 2026·8 min readTools

npm install errors: read the code, not the stack

Every npm ERR code names one cause. ERESOLVE, E404, EJSONPARSE and the rest, with what each one means, measured against real installs.

Read more
{ }
✦

Ready to write some code?

Put this into practice - start your first free lesson. No setup, no credit card.

Start learning free
Devpuff

Learn to code by doing. One tiny, playful lesson at a time.

Learn
ProgramsCoursesPricing
Company
AboutBlogResourcesAffiliates
Support
Help CenterContactStatus
Programs
Frontend DevelopmentFull-Stack DevelopmentReact DeveloperPython Developer
Courses
Advanced ReactAsync JavaScriptAsync PythonCSS BasicsCSS LayoutDSA Basics
Learn to Code
Learn JavaScriptLearn PythonLearn SQLLearn HTMLLearn CSSLearn ReactBrowse All Topics
Platform Comparisons
Devpuff vs CodecademyDevpuff vs Mimo
© 2026 Devpuff. All rights reserved.Privacy PolicyTerms and ConditionsCookies PolicyRefund Policy
Devpuff vs Sololearn
Devpuff vs freeCodeCamp
Read All Comparisons