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
M omelette.txt M pancakes.txt
git stash git status -s
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
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
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 experimentThe 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}
omelette.txt | 2 +- pancakes.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
git stash show -p stash@{1}
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
| Command | Restores the changes | Removes the stash entry |
|---|---|---|
git stash pop | yes | yes (unless there's a conflict) |
git stash apply | yes | no — useful to apply the same changes to several branches |
git stash drop stash@{n} | no | yes |
git stash clear | no | removes all stashes |
git stash apply stash@{1}
git stash drop stash@{1}
git stash list
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 recipeUntracked 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
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
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
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}
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.