{ by david linsin }

July 29, 2009

Git Stash

After a great talk on Git at the Java User Group Karlsruhe and a couple of other experiences, I started to really dig the Distributed Source Control Management (DSCM) notion and its advantages. A neat and quite helpful feature of Git is stashing.

The Git manual has as an exceptionally helpful description of stashing. They call it "Temporarily setting aside work in progress".

While you are in the middle of working on something complicated, you find an unrelated but obvious and trivial bug. You would like to fix it before continuing. You can use git-stash(1) to save the current state of your work, and after fixing the bug (or, optionally after doing so on a different branch and then coming back), unstash the work-in-progress changes.

$ git stash save "work in progress for foo feature"

This command will save your changes away to the stash, and reset your working tree and the index to match the tip of your current branch. Then you can make your fix as usual.

... edit and test ...
$ git commit -a -m "blorpl: typofix"

After that, you can go back to what you were working on with git stash pop:

$ git stash pop

Git's stashing feature saved me quite some trouble a couple of days ago, while working on a side project. I developed a feature on branch "B" and had quite a big change-set, while someone found a bug on the stable branch, let's call it "A".

Coming from SVN, I thought I had to check-in my changes in order to switch to Branch "A" and fix the bug. That's quite ugly, because it screws with your history of commits and even might break your builds. I know that there are other possibilities with SVN, like copying your changed files or creating a patch file. However, to me those all look like workarounds rather than solutions.

So I simply stashed my changes from branch "B" and got a clean branch with HEAD. I switched to branch "A" and was able to fix and commit the bug. After switching to branch "B" again, I simply poped the changes from the stash, as if I had never stopped working on the feature.

After working with Git for some time, I would really recommend people to switch to a DSCM. I'm not alone with this. SpringSource's DM server team migrated their repositories to Git a couple of weeks ago and they didn't hear any complaints from the community. No matter if you choose Git or Mercurial, the advantages of a DSCM really outweigh the initial costs of getting started.


Anonymous said...

Not so sure about this one. I am used to have multiple eclipse workspaces checked out in parallel for all branches and open projects. If I need to add a quick fix I eighter check out a copy of my project (in the same or different workspace) or I just work on a file level.

David Linsin said...

There are definitely other approaches to tackle this problem.

For me you describe exactly what I don't want to have on my file system: multiple copies of a project! I really don't need my project to be spread over multiple folders in x different versions. I want to the SCM to handle different versions for me.

With IntelliJ it's quite easy to switch from branch A to B in that you only type on the command line "git checkout B" and the project is switched. So no need for multiple copies of a workspace.

A MacLeod said...

You can also use git stash to create a branch in the midst of work. Imagine you have some uncommitted changes that did not initially seem to necessitate a branch, but now you have decided that they diverge enough that you need a branch.

git stash
git branch "newbranch"
git stash apply
git commit -am "shifting development to my branch."

Senzafine said...

@bernd, I felt the same way until I got comfortable with git. While your method works, git makes this type of task virtually effortless.

This is a common pattern for solutions git provides versus the alternatives.

Tom said...

I know this is an old post, but A MacLeod: you don't need to use stash, and that code won't actually switch to the created branch.

The quickest way to move uncommitted changes to new branch is simply to do:
git checkout -b new_branch


  • mail(dlinsin@gmail.com)
  • jabber(dlinsin@gmail.com)
  • skype(dlinsin)