Git: Stashing

Stash changes in a dirty working directory.

René Kulik on 30.01.2019

At some point you may need to stash your changes in a dirty working directory. For example when you did not commit your local changes yet but you want to pull in changes from a remote repository. Or you quickly want to checkout a different branch without the need of committing your progress.

For those situations, stashing is the recommended way to do so. In this post I will give you a brief overview of what stashing in git is and I will demonstrate the basic workflow. To fully understand the given examples, a fundamental knowledge about git is required.

Stashing?

Stashing enables you to save your local changes away and resets your working directory to the HEAD state. Stashed changes can be re-applied whenever you need them. It is even possible to use stashes multiple times.

Create

Given you made changes (files have to be tracked, but it does not matter if staged for commit or not) in a git directory which contains at least one commit:

~/git-stashing (master*) $ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   bar.txt

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:   foo.txt

To create a stash use git stash (or the equivalent git stash push). This will store your changes away and your working directory is clean again:

~/git-stashing (master*) $ git stash
Saved working directory and index state WIP on master: 377r7fd Initial commit
~/git-stashing (master) $ git status
On branch master
nothing to commit, working tree clean

It is also possible to add a description to a stash, which makes identification easier. You have to use the longer version git stash push and add -m <message>:

~/git-stashing (master*) $ git stash push -m "Stash with message"
Saved working directory and index state On master: Stash with message

List

git stash list displays a list of all your stashes:

stash@{0}: On master: Stash with message

Show

Inspect the latest stash using git stash show:

~/git-stashing (master) $ git stash show
bar.txt | 0
foo.txt | 1 +
2 files changed, 1 insertion(+)

If you have multiple stashes, provide an index to inspect a specific one:

~/git-stashing (master*) $ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   baz.txt

~/git-stashing (master*) $ git stash
Saved working directory and index state WIP on master: 377r7fd Initial commit

~/git-stashing (master) $ git stash list
 stash@{0}: WIP on master: 377r7fd Initial commit
 stash@{1}: On master: Stash with message

~/git-stashing (master) $ git stash show 0
baz.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)

~/git-stashing (master) $ git stash show 1
bar.txt | 0
foo.txt | 1 +
2 files changed, 1 insertion(+)

Pop

By using git stash pop the latest stash will be removed from the stash list and applied to your working directory (provide an index to pop a specific stash):

~/git-stashing (master) $ git stash list
stash@{0}: WIP on master: 377r7fd Initial commit
stash@{1}: On master: Stash with message

~/git-stashing (master) $ git stash pop
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   baz.txt

Dropped refs/stash@{0} (24998f6d9e1729ecfc06b3a4a053f1d8rdd2b240)

~/git-stashing (master*) $ git stash list
stash@{0}: On master: Stash with message

Apply

git stash apply adds the latest stash to your working directory but keeps the stash remaining in the list for further usage (provide an index to apply a specific stash):

~/git-stashing (master*) $ git stash list
stash@{0}: On master: Stash with message

~/git-stashing (master*) $ git stash apply
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   bar.txt
	new file:   baz.txt

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:   foo.txt

Dropped refs/stash@{0} (3b0d45285ea3a1d0ebc4f6224db8a6143bade95e)

~/git-stashing (master*) $ git stash list
stash@{0}: On master: Stash with message

Drop

To remove the latest stash from the list without applying it, use git stash drop (provide an index to drop a specific stash):

~/git-stashing (master*) $ git stash list
stash@{0}: On master: Stash with message

~/git-stashing (master*) $ git stash drop
Dropped refs/stash@{0} (f320e2631b414fe9230c1d84d7f09339ac8918fd)

Oh My Zsh aliases

A workflow tip from my side to close up this post - use Oh My Zsh! It comes with a bunch of useful and convenient aliases for git, including shortcuts for stashing:

gsta='git stash save'
gstaa='git stash apply'
gstall='git stash --all'
gstc='git stash clear'
gstd='git stash drop'
gstl='git stash list'
gstp='git stash pop'
gsts='git stash show --text'

For further information about git stashing, have a look at the official documentation at https://git-scm.com/docs/git-stash