Fun with git stash

If you're anything like me, the only times you've ever used git stash it went something like this: In the middle of working on branch A you decided you should test something out on branch B. So you quickly run git stash, checkout branch B and test something, then come back to branch A, run git stash apply and pick back up where you left off.

Well it turns out git stash is much more powerful than that, and we've all been missing out for years. I always knew somewhere in the back of my head that git stash operated some kind of stack, but I just kept happily pushing things onto the stack without worrying about what that really meant.

One day I decided to take a look at git help stash and I suddenly realized I could be getting a lot more use out of this little command. First I learned about the list subcommand, which shows the entire contents of that stack. The first time I tried it out it was a mess:

# git stash list
stash@{0}: WIP on master: ad4304a fixed bug
stash@{1}: WIP on master: bffb5b9 added feature
stash@{2}: WIP on master: 4a70758 it works!
stash@{3}: WIP on master: 4a70758 it works!
stash@{4}: WIP on feature-a: d5d384a wow this is great
stash@{5}: WIP on master: d2abda9 finally fixed it
...

What happened here? It turns out every time I had run git stash before I knew what I was doing I was pushing a new stash onto the stack. Then when I got my changes back by running git stash apply, git just peeked at the most recent stash , applied its changes, and left it sitting on the stack. There's another command, pop, which applies the stash and pops it off the stack.

So every single stash I've ever created is just hanging out here on the stack, and that is reflected in the git stash list output.

So there's a stack? So what?

So all I've really learned at this point is that I should use pop instead of apply to make sure I clean up after myself, but does this stack let me do anything else?

For a lot of projects I have a few small changes I find myself making and undoing all the time. For example changing the configuration to point to a development server, or adding some sort of debug output. I realized that I can use the stash stack to store these various patches and apply them at will.

My new stash Workflow

If you run git stash save explicitly instead of the shortcut, git stash, you can specify a message for the stash, something more descriptive than "WIP on ...", like git stash save add debug info. So now, after adding a few useful stashes, my stack looks like this:

# git stash list
stash@{0}: On master: add debug info
stash@{1}: On master: use local server

Much better! Now how do I use these patches? Since I want to apply the patch while still keeping it around on the stack, I can go back to my old friend apply. It turns out you can also specify which stash you want to apply, so I can switch to the local server by running git stash apply stash@{1}.

Now what if I've made some other changes, and I'd like to "unapply" that stash? There's no built-in way to do it, but this SO answer points out a way to hack it together, by printing out the patch and applying it in reverse:

git stash show -p stash@{1} | git apply --reverse

These commands are useful, but a little bit wordy. I added some aliases to ~/.gitconfig to make it easier:

stapply = "!f() { git stash apply stash@{$1}; }; f"
stunapply = "!f() { git stash show -p stash@{$1} | git apply --reverse; git status; }; f"

Now all I have to type is git stapply 1 and git stunapply 1 to toggle the local server on and off.