Git Stash
You know how to git push and git pull.
You've worked with git merge.
When you're feeling spunky, you may even git rebase. 🤓
But there's one git command you've avoided: git stash. This exotic tool has baffled you. But no longer.
Let's see how git stash can make your workflow as smooth as my baby's bottom.
When would I use this?
git stash saves your local changes changes and reverts the working directory to the last commit (i.e. HEAD). That's useful when you're not ready to make a record in the commit history. And that might happen in a few scenarios.
Scenario 1: The Interruption
You're in deep work, cranking out some code for a new feature.
Ping. The boss demands you fix a bug in the main branch ASAP. But you're not in a good spot to save your work. 🙁
> git status
On branch new-feature
Untracked files:
(use "git add <file>..." to include in what will be committed)
awesome_code_here.txt
nothing added to commit but untracked files present (use "git add" to track)
That new file awesome_code_here.txt isn't ready to commit. No worries. You stash your dev work on the new-feature branch:
> git stash -u -m "I'll be back, baby"
Saved working directory and index state On new-feature: I'll be back, baby
> git status
On branch new-feature
nothing to commit, working tree clean
git stash saves your work and resets the working directory. (We'll talk about the -u and -m flags later.)
Then you jump over to the main branch to fix the bug. When you're done with battle, you return to your work:
> git switch main
Switched to branch 'main'
> # fix the bug...
> git switch new-feature
Switched to branch 'new-feature'
> git status
On branch new-feature
nothing to commit, working tree clean
Once back on the new-feature branch, you use git pop to reapply the changes saved in the stash. This restores your working state before your boss summoned you. Now you continue working on awesome_code_here.txt.
> git stash pop
Already up to date.
On branch new-feature
Untracked files:
(use "git add <file>..." to include in what will be committed)
awesome_code_here.txt
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (d32db6e265fd2c68d0291dfc222441a151eff6c2)
Without git stash, you'd make a temporary commit on the new-feature branch, fix the bug on main, return to new-feature, and perform git gymnastics with something like git reset --soft HEAD^ to undo the temporary commit. 🤢
So just use git stash.
Scenario 2: Oops, I'm working on main
You start the day eager to work. You make changes and are about to commit... only to realize you're still on the main branch. 😱
> git status
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: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
Unfortunately, your team prohibits direct commits to main. These changes to file.txt should have been made in a dev branch.
You could undo your work and manually reapply the changes in a dev branch...
Or you stash the work you have, open a dev branch, and apply the stash there:
> git stash -m "My exciting work"
Saved working directory and index state On main: My exciting work
> git status
On branch main
nothing to commit, working tree clean
> git switch -c dev-branch
Switched to a new branch 'dev-branch'
> git stash pop
On branch dev-branch
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: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (c39ef47fb2a7bcd21a316e0c604ced62b92d491d)
Now the changes to file.txt are on the branch dev-branch. Commit the changes in this branch, and push the dev branch to remote.
Then open a pull request for your team to see your sensational code!
Scenario 3: Pulling into a stale branch
You've been working on a dev branch with your teammate. The branch is tracked to follow a remote branch. You make changes to the dev branch on your computer... but then realize you don't have your teammate's latest changes. You run git pull to get his updates and get this scary message:
> git pull
Updating 9601e5e..bbe0ee6
error: Your local changes to the following files would be overwritten by merge:
file.txt
Please commit your changes or stash them before you merge.
Aborting
Git's complaining that you made changes to file.txt, and an attempt to pull changes from remote would overwrite your change.
That's okay. You stash your changes as the error message recommends. Then run git pull to get the latest version of the branch.
> git stash -m "Wait for me"
Saved working directory and index state On dev: Wait for me
> git pull
Updating 9601e5e..bbe0ee6
Fast-forward
file.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Now that your local branch is in sync with the remote branch, you pop the stash.
> git stash pop
Auto-merging file.txt
On branch dev
Your branch is up to date with 'origin/dev'.
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: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (0bed94bacac95e7d33f43642d7e9c2c102a376cd)
Git applies the stash state to the branch's working directory. Then you re-stage the updated file and push your own commit to remote.
> git commit -a -m "Here's my change, Tommy"
[dev a512cb1] Here's my change, Tommy
1 file changed, 1 insertion(+), 1 deletion(-)
> git push
...
That's how you work with colleagues! Don't forget to tell Tommy to pull your changes.
The "git stash" Cheatsheet
Create a Stash
As you've seen, creating a stash is a simple as running git stash. Git will take any changes you've made to tracked files and move them to the stash list. It will also revert the working directory to the last commit.
Include untracked files by running git stash -u (u for untracked). Or write a helpful message with the -m flag.
View Stashes
Run git stash list to see the stash objects:
> git stash list
stash@{0}: On main: Super secret new feature
stash@{1}: On main: Oops, worked on main
stash@{2}: WIP on new-feature: a45c0a7 Initial commit
Here, you have 3 stashes. The newest stash has an index of 0 and is identified as stash@{0}. The next most recent stash is stash@{1}, and so on. When a new stash is created, all existing stashes move down the list, and the new stash takes the place of stash@{0}.
The output of git stash list also gives the branch that was current when the stash was made along with the stash message.
Apply a Stash
You have a few ways to manage stashes. To re-apply the changes from a stash, run git stash pop. That will apply the latest stash to the working directory AND remove the stash from the list.
Or hit git stash apply. That will apply the latest stash like git stash pop but still keep the change in the stash list.
Without any arguments, git stash pop and git stash apply will apply the 0th stash. To target another stash, pass the stash index to the command. For example, git stash apply stash@{2} applies the stash at index 2.
View Stash Content
Not sure what a stash contains? Check it out with git stash show:
> git stash show stash@{1}
file.txt | 2 ++
1 file changed, 2 insertions(+)
You can even see the specific changes with the patch flag (-p):
> git stash show stash@{1} -p
diff --git a/file.txt b/file.txt
index ce01362..bc47e45 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,3 @@
hello
+
+making a change here
Remove Stashes
Ready to clean up your stash list? Run git stash drop stash@{2} to remove the stash in the 2nd index position from the list.
> git stash drop stash@{2}
Dropped stash@{2} (74994016db843c9f3ff2b7c8d355afe084db1ec2)
Or run git stash clear to remove all stashes. Be careful with this command! You don't want to delete stashes too quickly.
That's all you need to know about git stash for day-to-day work. git stash makes it easy to save your current unfinished work without mucking up the commit history. This frees you to work on something else and then come back to the stash content.
Without stashes, you'd have to make temporary commits, switch branches, and then run git gymnastics with git reset to clean up the commit history. 😬 Life's too short to mess with that.
Want more tips to improve the coding experience? Let me know; my stash is ready.