Table of Contents

Introduction

If you've stashed something, you'll eventually want it back. Most tutorials reach for git stash pop, but git stash apply does the same restore without deleting the stash afterwards. That small difference makes apply the calmer choice when you're not completely sure what's in the stash, or when you want the same changes on more than one branch.

In this article, we'll:

  1. Watch git stash apply bring a stashed change back into the working directory
  2. See that the stash list is exactly the same afterwards
  3. Cover --index, applying an older entry, and what happens on a conflict

What is git stash apply?

git stash apply takes a stash entry (the newest one, stash@{0}, unless you name another), and merges the changes it recorded into your current working directory. The entry itself stays on the stash list. Nothing about your branches or commits changes.

By default everything comes back as unstaged edits, even changes that were staged when you stashed them. git stash apply --index also restores what was in the staging area.

Watch it happen

Our sample repo has one entry in the stash, made on main while sitting on 8c02d5b, "Update dependencies". Here's git stash apply:

  1. Before: the working directory and staging area are clean, and the stash holds a change to app.py.
  2. Git applies the stashed change, so app.py is modified in the working directory, unstaged.
  3. main and HEAD stay on 8c02d5b, and stash@{0} is still in the stash. Applying reads from the stash without removing anything from it.

Before and after

git status --short before shows nothing at all. After, it shows one modified file:

 M app.py

git stash list is identical before and after:

stash@{0}: WIP on main: 8c02d5b Update dependencies

When the apply finishes, Git prints the same report you'd get from git status, so you can see what came back:

The raw git output, if you want to read along in text

git log --oneline --graph --all

before

*   258f6e3 (refs/stash) WIP on main: 8c02d5b Update dependencies
|\  
| * 09e56b2 index on main: 8c02d5b Update dependencies
|/  
* 8c02d5b (HEAD -> main) Update dependencies
* a0b2db3 Add user settings page
| * 1117a34 (feature) Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

after

*   258f6e3 (refs/stash) WIP on main: 8c02d5b Update dependencies
|\  
| * 09e56b2 index on main: 8c02d5b Update dependencies
|/  
* 8c02d5b (HEAD -> main) Update dependencies
* a0b2db3 Add user settings page
| * 1117a34 (feature) Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

what git printed

On branch main
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:   app.py

no changes added to commit (use "git add" and/or "git commit -a")

In the raw log you can also spot the stash itself: 258f6e3, "WIP on main: 8c02d5b Update dependencies", is a commit with two parents, 8c02d5b and 09e56b2 ("index on main"), which holds what was staged. It's still in the log after the apply, under refs/stash, because nothing deleted it.

apply versus pop

git stash pop is apply followed by git stash drop, and the drop only happens if the apply went through without conflicts. So the two commands put exactly the same changes into your working directory. The only question is whether you want the entry to hang around afterwards.

Keeping it is useful when:

  • you want to check the result before throwing the stash away
  • you want the same changes on several branches, by switching and applying again
  • you're not sure stash@{0} is the one you meant

Once you're happy, git stash drop removes the entry by hand.

I keep one stash around on purpose: a handful of debug print statements I like to have when I'm chasing something. I apply it on whatever branch I'm on, throw the edits away with git restore when I'm done, and the stash is still there the next time.

Is it safe?

apply only adds changes to your working directory and never removes the stash, so the stashed work can't be lost by running it. Git also refuses to start if you have uncommitted edits to a file the stash would overwrite, and tells you which files are in the way.

The one surprise is a conflict. If main has changed the same lines since you stashed, Git writes conflict markers into the file and stops. Resolve the file as you would after a merge, and since apply never drops anything, the stash entry is still there if you want to start over.

Useful forms

  • git stash apply stash@{2} applies an older entry. git stash list shows the numbers.
  • git stash apply --index restores the staging area too. If the staged part no longer applies cleanly, Git refuses, and you can retry without --index.
  • git stash apply <hash> applies a stash commit by its hash, which is how you get back one that was dropped.
  • git stash show -p stash@{0} shows the diff before you apply anything. Every subcommand and flag is in the git stash documentation.

How to undo it

In our example the working directory was clean before the apply, so throwing the restored edits away gets you back to where you started:

git restore app.py

That's only safe because the stash still has the changes. If you had other edits in app.py before applying, git restore would take those too.

Here is the stash being made in the first place:

Try it on your repository

pip install git-sim
git-sim stash apply

git-sim shows which files the stash would put back in your working directory, without touching them.

Common questions

What is the difference between git stash apply and git stash pop?

Both restore the same changes. pop also deletes the stash entry if the restore succeeds, while apply always keeps it.

How do I apply a specific stash?

Name it: git stash apply stash@{2}. Run git stash list first to see which number is which.

Why did my staged changes come back as unstaged?

apply restores file contents only, unless you add --index, which also restores what was staged.

Does git stash apply delete the stash?

No. The entry stays on the list until you run git stash drop, or git stash pop on it.

Summary

In this article, we watched git stash apply bring app.py back from the stash while the entry stayed on the list, and covered --index, picking an older entry, and what a conflict looks like.

Next steps

git stash drop removes the entry once you're done with it. git stash pop does the apply and the drop in one step.