git stash is a surprisingly powerful tool that lets you temporarily set aside uncommitted changes without committing them, so you can switch contexts and come back later.

Let’s see it in action. Imagine you’re working on a new feature, feature-A, and you’ve made a few changes:

$ git status
On branch feature-A
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   src/app.js
    modified:   src/utils.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    src/new_component.js

You’ve modified src/app.js and src/utils.js, and added a new file, src/new_component.js, which isn’t even tracked by Git yet. Suddenly, an urgent bug report comes in for the main branch. You can’t commit your unfinished work on feature-A because it’s not ready. This is where git stash shines.

To save your current work, you run:

$ git stash save "WIP: Implementing feature A, interrupted by urgent bug"
Saved working directory and index state WIP on feature-A: a1b2c3d Initial commit for feature A

The save subcommand is optional, but it’s good practice to provide a descriptive message. Now, check your status:

$ git status
On branch feature-A
nothing to commit, working tree clean

Git has perfectly reverted your working directory to match the last commit. The modified files are back to their committed state, and the untracked file src/new_component.js has been removed from your working directory. Your changes are safely stored in a "stash" – a special stack of uncommitted changes.

You can now switch to the main branch, fix the bug, commit it, and then switch back to feature-A. To retrieve your stashed work, you use git stash pop:

$ git checkout main
Switched to branch 'main'
# ... fix the bug, commit ...
$ git checkout feature-A
Switched to branch 'feature-A'
$ git stash pop
On branch feature-A
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   src/app.js
    modified:   src/utils.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    src/new_component.js

git stash pop applies the most recent stash to your working directory and then removes that stash from the stash stack. Notice that both the modified tracked files and the untracked file are back.

If you want to see what stashes you have, you can use git stash list:

$ git stash list
stash@{0}: On feature-A: WIP: Implementing feature A, interrupted by urgent bug
stash@{1}: On main: Fix critical login issue

This shows you have two stashes. stash@{0} is the most recent one. If you wanted to apply an older stash, say stash@{1}, you’d use git stash apply stash@{1}. apply is like pop but it doesn’t remove the stash from the stack, which is useful if you want to reapply the same changes to multiple branches.

git stash also has a powerful option to stash untracked files. By default, git stash only stashes changes to tracked files. To include untracked files, use git stash -u or git stash --include-untracked:

$ git stash -u "WIP: Feature B, including new config"
Saved working directory and index state On feature-B: 9d8c7b6 Add initial structure for feature B

Now, when you git stash pop, that new untracked file will also be restored.

There’s also git stash --all which stashes untracked files and ignored files. This is less common but can be useful if you have build artifacts or temporary files you want to sweep away temporarily.

A common point of confusion is how git stash handles merge conflicts when popping. If you have local changes that conflict with the stashed changes, git stash pop will stop and tell you about the conflicts, leaving the stash on the stack. You’ll need to resolve the conflicts manually, then git add the resolved files, and then use git stash drop to remove the stash from the stack.

The most surprising thing about git stash is its ability to stash only specific files or even parts of files. This is done with git stash --patch. When you run this, Git will walk you through each hunk of changes in your modified files, asking if you want to stash it. You can type y to stash the hunk, n to skip it, s to split the hunk into smaller pieces, or q to quit. This granular control means you can meticulously curate what goes into your stash, leaving other changes behind in your working directory.

Once you’ve applied a stash, or if you decide you don’t need it anymore, you can remove it from the list using git stash drop stash@{n}. If you want to clear all stashes, you can use git stash clear.

What happens when you have multiple stashes and you pop the most recent one, but there are still conflicts with your current working directory? Git will leave the conflicting changes in your working directory as if they were new modifications, and it will not drop the stash from the stack. You’ll then need to resolve these conflicts manually, commit them (or stash them again), and then explicitly git stash drop the applied stash.

Want structured learning?

Take the full Git course →