Tuesday, January 13, 2015

Git Stash - Saving Stuff for Later

I ran across another great feature in Git today (it's always cool to discover stuff that's new to you).

I was experimenting with my sample code that shows how to use Task and await (working on how to show cancellation tokens in action). I got to the point where I had some changes that I wanted to keep, but I wasn't quite ready to commit them yet. On top of that, I really wanted to apply these changes to a new branch (and not to "master" yet).

Jeremy's 'stache (2009)
TFS has the concept of shelving changes -- putting a change set into source control without applying it to the branch. I wondered if Git had a similar feature. After a quick search online, I found that it does: stash.

Note: Git articles are collected here: Learning Git.

Stashing Changes
The "stash" command is pretty easy to use. It's basically a way to push a change set onto a stack. The changes can then be popped off when we want to retrieve them. We can have multiple stashed items, but we'll just use one change set for our example here.

Uncommitted Changes
First, let's run "git status" to see our current state:

git status

This shows that we are currently on the "master" branch, and we have 4 modified files waiting to to be committed.

But instead of committing the files, we'll "stash" them.

Stashing Changes
Now it's time to save our changes for later.

git stash & git status

First, we call "git stash". This saves the changes in our working directory into the stash list. (And "WIP" stands for "work in progress" -- this shows up quite a bit.)

Next, we run "git status" and see that there are now no pending changes for "master". Our working directory has been restored to the previously committed version of "master".

This has the same effect on our working directory as if we had discarded pending changes. But instead of discarding the changes outright, we've saved them off so we can access them later.

To see the list of stashed items, we just use "git stash list".

git stash list

This shows that we have one stashed item.

Retrieving Stashed Items
To restore these changes, we just use "git stash apply".

git stash apply

This shows that we now have uncommitted changes on our "master" branch -- the same changes that we saved off in our stash.

Deleting a Stash
Applying a change set from our stash does not change the stashed items at all. If we display the stashed items, we'll see that they are all still there.

git stash list

We can get rid of an item by using the "git stash drop" command.

git stash drop & git stash list

Now when we list our items, we see that the stash is empty.

Note that "drop" just removes the first item -- popping it off the stack. If we had multiple items in our stash, only the first one would be affected.

For information on dealing with multiple items, check out the documentation: Git Tools - Stashing.

Creating a Branch from Uncommitted Items
So we've seen how "stash" works in general. But all we've done so far is save off a change set and then re-apply it to our "master" branch. Our changes are still uncommitted. We're back in the same state we were in when we started this exercise.

What I really want to do is create a new branch based on these uncommitted changes. And it turns out that "stash" has that ability as well.

Stashing Changes
We'll start by stashing our changes again with "git stash".

git stash & git stash list

After running this command, we use "git stash list" to see that our changes were saved off successfully.

Creating a New Branch
Before creating a new branch, let's use "git branch" to see our existing branches.

git branch

This shows that we have 9 branches, and that we're currently on "master".

To create a new branch from our stashed items, we use "git stash branch" and then give it the name of the new branch.

git stash branch 09-CancellationBasics

This shows that we are now on a branch called "09-CancellationBasics", and we have uncommitted changes.

One other thing to note about this process, the stashed items are automatically dropped (as we can see in the last line of the output).

And just to verify, let's re-list our branches.

git branch

This confirms the new branch has been created, and it is the current branch.

From here, we can move forward with committing changes and doing whatever else we want. This seems like a great way to move uncommitted changes to a new branch.

Visual Studio (Lack of) Support
Previously, we saw there there is quite a bit of support for Git in Visual Studio: Git Integration in Visual Studio 2013 and Getting Used to Git in Visual Studio: Branches.

Unfortunately, "stash" is not supported out-of-the-box in Visual Studio 2013. I had a feeling that not all Git features were supported -- it's difficult to get one-to-one parity between command line and visual tools. So, I'm really glad that I've been spending time with Git on the command line. This has made it much easier for me to pick up this functionality.

Wrap Up
I'm still learning Git as I go. I've often found that just-in-time learning works well for me -- learning about features when I have a use for them. And I was very happy to see the functionality that is available with "stash". I often do experiments that I don't want to save, but I don't want to completely discard them either. This ability to save changes for later (and also easily move them to a new branch) will come in handy in the future.

Happy Coding!

No comments:

Post a Comment