If you've been working with Git long enough, you've probably had times where you made changes to your codebase, but needed to switch branches or work with the latest working version of your code. However, you don't want to lose the changes you've made already, but they're not yet ready to commit the updates since they're not finished. What should you do?
Git Stash
Luckily, Git provides a mechanism to handle cases like this through the command git stash
. The stash
command takes the uncommitted changes in your working directory, both the updated tracked files and staged changes, and saves them.
Let's say you're working on a new feature and you made some modifications to your code, and you now have one or more files with uncommitted modifications:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index.js
no changes added to commit (use "git add" and/or "git commit -a")
However, the changes aren't finished, and you need to switch to a different branch to quickly fix a bug before continuing on with the current feature. To avoid losing the current updates you've made, you can just stash the changes instead and get them back later without messing up your commit history.
$ git stash
Saved working directory and index state WIP on master: bbf6ef9 Initial commit
HEAD is now at bbf6ef9 Initial commit
As you can see, HEAD
is now back to our last commit, which in this case is the initial commit. To verify, look for changes using git status
:
$ git status
On branch master
nothing to commit, working tree clean
We're back to where we started as if we never made the changes at all! Now you can go off and fix that bug.
But what about restoring your changes? To get them back, we can simply use the apply
sub-command, which takes the last-stashed changes and puts them back into your working directory.
$ git stash apply
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index.js
no changes added to commit (use "git add" and/or "git commit -a")
And just like that, you have your changes back.
Advanced Features
In the examples above, we used stash
in the simplest context. As we tend to find out in our day-to-day programming, real-world use-cases aren't usually that simple. What if, for example, you end up needing to stash changes from your working directory multiple times? Luckily, stash
allows you to do just that. Technically, when you stash changes, Git puts the changes on a stack, which can then be pulled off in a LIFO (last in, first out) order. You're able to view this stack using the list
subcommand.
$ git stash list
stash@{0}: WIP on master: 7513525 Fixed console output
stash@{1}: WIP on master: 91f33cc Fixed output punctuation
stash@{2}: WIP on master: bbf6ef9 Initial commit
stash@{3}: WIP on master: bbf6ef9 Initial commit
The stashed work at the top of the list is what you'll get when using the apply
command without any extra arguments. If there is a different stash you'd like to get instead, you can specify it using the identifier at the beginning of each line. For example, to get the second stash, you would use the following:
$ git stash apply stash@{1}
On branch master
nothing to commit, working tree clean
You may notice that after using the apply
subcommand, the stash will still be on the stack. In order to apply it and remove it from the stack, use pop
instead.
$ git stash pop stash@{0}
On branch master
nothing to commit, working tree clean
Dropped stash@{0} (9079b4ffdf46574701cffcd68eb4feba80ebcf72)
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
This stash is now no longer in our stack:
$ git stash list
stash@{0}: WIP on master: 91f33cc Fixed output punctuation
stash@{1}: WIP on master: bbf6ef9 Initial commit
stash@{2}: WIP on master: bbf6ef9 Initial commit
But what if you want to remove a stash without applying it to your current working directory? This can be achieved with drop
, which works much like apply
and pop
syntactically:
$ git stash drop stash@{2}
Dropped stash@{2} (5483fdec3496572c8b943504b6029d45a7999453)
And, as expected, that stash was not applied and it is gone from the stash stack:
$ git status
On branch master
nothing to commit, working tree clean
$ git stash list
stash@{0}: WIP on master: 91f33cc Fixed output punctuation
stash@{1}: WIP on master: bbf6ef9 Initial commit
Conclusion
Unsurprisingly, Git has a solution for most problems that arise in version control since it's been around for such a long time. Here we've seen how to handle the use-case where you have changes in your working directory, but you want to switch branches and not commit the unfinished changes. The stash
command can be very powerful, and there are more features to it than what was covered here, like various flags that are available, which we'll save for another article.