My blog, keeping you up-to-date on my latest news.

 

Stashing your work with git

Linux • 2013-06-08 • 2 Comments

 

What is Git Stash?

Often when you use git in collaboration, things have some changes and you want to switch branches to work on another tasks. The problem is, you don't want to do a commit of half-done work and don't want to loose what you already do.

So the anwser to this issue is the git stash command.

Start the Stashing

To demonstrate, you will go into your project and start working on a couple of files.
If you run git status, you can see your dirty state:

got@GoT:$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	modified:   public/index.php
#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   init_autoloader.php
#

Now you want to switch branches without loose your changes, so you'll stash the changes.
To push a new stash onto your stack, just run git stash:

got@GoT:$ git stash
Saved working directory and index state WIP on master: 7fe85b2 Quick fix with translations
HEAD is now at 7fe85b2 Quick fix with translations

Your working directory is clean:

got@GoT:$ git status
# On branch master
nothing to commit (working directory clean)

At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack.
To see which stashes you've stored, you can use git stash list:

got@GoT:$ git stash list
stash@{0}: WIP on master: 7fe85b2 Quick fix with translations

You can reapply the one you just stashed by using the command shown in the help output of the original stash command: git stash apply.
If you have more than one stash in your list and you want to apply one of the older stashes, you can specify it by naming it, like this: git stash apply stash@{1}.

got@GoT:$ git stash apply
# On branch master
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   init_autoloader.php
#	modified:   public/index.php
#
no changes added to commit (use "git add" and/or "git commit -a")

You can see that Git re-modifies the files you uncommitted when you saved the stash.
You can save a stash on one branch, switch to another branch later, and try to reapply the changes.
You can also have modified and uncommitted files in your working directory when you apply a stash, git gives you merge conflicts if anything no longer applies cleanly.

The changes to your files were reapplied, but the file you staged before wasn't restaged.
To do that, you must run the git stash apply command with a --index option to tell the command to try to reapply the staged changes.

got@GoT:$ git stash apply --index
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#      modified:   public/index.php

#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#
#      modified:   init_autoloader.php
#

The apply option only tries to apply the stashed work, so the stash is always is the stack.
To remove it, you can run git stash drop with the name of the stash to remove:

got@GoT:$ git stash list
stash@{0}: WIP on master: 7fe85b2 Quick fix with translations
got@GoT:$ git stash drop
Dropped refs/stash@{0} (e11db9f54e7c01a469ca56b810793d796dcdacf0)

or

got@GoT:$ git stash drop stash@{0}
Dropped stash@{0} (e11db9f54e7c01a469ca56b810793d796dcdacf0)

You can also run git stash pop to apply the stash and then immediately drop it from your stack.

Un-applying a Stash

In some use case scenarios you might want to apply stashed changes, do some work, but then un-apply those changes that originally came from the stash.
Git does not provide such a stash unapply command, but it is possible to achieve the effect by simply retrieving the patch associated with a stash and applying it in reverse:

got@GoT:$ git stash show -p stash@{0} | git apply -R
Again, if you don't specify a stash, Git assumes the most recent stash:
got@GoT:$ git stash show -p | git apply -R

If you want you can create an alias and effectively add a stash-unapply command to your git:

got@GoT:$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
got@GoT:$ git stash
$ #... some stuff
got@GoT:$ git stash-unapply

Creating a Branch from a Stash

If you stash some work, leave it there for a while, and continue on the branch from which you stashed the work, you may have a problem reapplying the work, because if the apply tries to modify a file that you've modified, you will get a merge conflict.
So the easiest way to test the stashed changes again, you can run git stash branch, which creates a new branch for you, checks out the commit you were on when you stashed your work, reapplies your work there, and then drops the stash if it applies successfully:

got@GoT:$ git stash branch myNewBranch
Switched to a new branch "myNewBranch"
# On branch myNewBranch
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#      modified:   public/index.php
#
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#
#      modified:   init_autoloader.php
#
Dropped refs/stash@{0} (e11db9f54e7c01a469ca56b810793d796dcdacf0)

<< Back to Blog Discuss this post

 

Comments

 
  1. Mr. Color

    Thanks, I didn't know about this!

  2. Thomas

    Very interesting post. Thanks for sharing.

 

Add a comment

 

Categories