Stashing Changes

You're in the middle of something when an urgent task comes in, and your changes aren't ready to commit. git stash puts your uncommitted work on a shelf and gives you a clean working tree; later you take it back off the shelf and carry on.

Stashing and restoring

Sam is halfway through changing two recipes:

$
echo "Pancakes: flour, milk, eggs, buttermilk" > pancakes.txt
echo "Omelette: eggs, butter, spinach" > omelette.txt
git status -s
Output
 M omelette.txt
 M pancakes.txt
$
git stash
git status -s
Output
Saved working directory and index state WIP on main: 27b2aae Add recipes

The changes are saved and the working tree is back to the last commit. Sam can now switch branches, pull, or fix something urgent. When done, bring the work back with pop:

$
git stash pop
Output
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:   omelette.txt
	modified:   pancakes.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (6ea25b2ea0ffb5e94bc73f4c7ceaf3b2af20a250)

The changes are back as they were, and the stash entry is removed.

Naming your stashes

Stashes pile up. Give each one a message so you can tell them apart later:

$
git stash push -m "buttermilk pancakes experiment"
echo "Granola: oats, honey" > granola.txt
git add granola.txt
git stash push -m "new granola recipe"
git stash list
Output
Saved working directory and index state On main: buttermilk pancakes experiment
Saved working directory and index state On main: new granola recipe
stash@{0}: On main: new granola recipe
stash@{1}: On main: buttermilk pancakes experiment

The stash is a stack: stash@{0} is always the most recent. (Notice that staged new files like granola.txt are stashed too.)

Looking inside a stash

$
git stash show stash@{1}
Output
 omelette.txt | 2 +-
 pancakes.txt | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
$
git stash show -p stash@{1}
Output
diff --git a/omelette.txt b/omelette.txt
index b4927c2..082a5f9 100644
--- a/omelette.txt
+++ b/omelette.txt
@@ -1 +1 @@
-Omelette: eggs, butter
+Omelette: eggs, butter, spinach
diff --git a/pancakes.txt b/pancakes.txt
index a05992e..d767488 100644
--- a/pancakes.txt
+++ b/pancakes.txt
@@ -1 +1 @@
-Pancakes: flour, milk, eggs
+Pancakes: flour, milk, eggs, buttermilk

pop vs. apply

CommandRestores the changesRemoves the stash entry
git stash popyesyes (unless there's a conflict)
git stash applyyesno — useful to apply the same changes to several branches
git stash drop stash@{n}noyes
git stash clearnoremoves all stashes
$
git stash apply stash@{1}
git stash drop stash@{1}
git stash list
Output
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:   omelette.txt
	modified:   pancakes.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped stash@{1} (bac81474d7b99864e498c3c34ef8f7a74ddce6cf)
stash@{0}: On main: new granola recipe

Untracked and ignored files

By default, stash only takes changes to tracked files (and staged new files). Brand-new untracked files stay in your working tree:

$
echo "Porridge: oats, milk" > porridge.txt
git stash
Output
No local changes to save

Nothing was stashed. Add -u (--include-untracked) to include untracked files, or -a (--all) to include ignored ones as well:

$
git stash -u
git status -s
git stash pop
Output
Saved working directory and index state WIP on main: 27b2aae Add recipes
Already up to date.
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	porridge.txt

nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (53063a7bbae6dd75018b42e44dd415985c00a394)

Stashing only some files

Name paths after -- to stash just those, or use -p to pick hunks interactively. --staged (Git 2.35+) stashes only what you've staged:

$
echo "Pancakes: flour, milk, eggs, cinnamon" > pancakes.txt
echo "Omelette: eggs, butter, ham" > omelette.txt
git stash push -m "omelette only" -- omelette.txt
git status -s
Output
Saved working directory and index state On main: omelette only
 M pancakes.txt
?? porridge.txt

Conflicts when popping

If the files changed in the meantime, applying a stash can conflict just like a merge. Resolve the markers, git add the files, and — because a conflicted pop keeps the entry — drop the stash yourself once you're happy.

Turning a stash into a branch

If a stash has grown into a real piece of work, git stash branch creates a branch from the commit you were on when you stashed, applies the stash there and drops it — avoiding any conflicts with later changes:

$
git stash branch omelette-ideas stash@{0}
Output
M	pancakes.txt
Switched to a new branch 'omelette-ideas'
On branch omelette-ideas
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:   omelette.txt
	modified:   pancakes.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	porridge.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped stash@{0} (c9f385fae97412e4762a14742876414ea5ada2a1)

Stash is for short breaks

Stashes are local, easy to forget, and anonymous unless you name them. For anything you'll come back to in more than a day, a work-in-progress commit on a branch is safer: it shows up in git branch, you can push it as a backup, and you can tidy it later with an amend or interactive rebase.

Try it yourself

Edit two tracked files and create one untracked file. Stash everything with a message (remember -u), check that git status is clean, switch to another branch and back, then pop the stash and confirm all three changes returned.