git-stash vs. git-branch

Git

Git Problem Overview


In a previous Git question, Daniel Benamy was talking about a workflow in Git:

> I was working on master and committed some stuff and then decided I wanted to put that work on hold. I backed up a few commits and then branched from before I started my crap work.

He wanted to restore his working state to a previous point in time without losing his current changes. All of the answers revolved around, in various ways, something like

git branch -m master crap_work
git branch -m previous_master master

How does this compare to git stash? I'm a bit confused trying to see what the different use case here when it seems like everything git stash does is already handled by branching…


@Jordi Bunster: Thanks, that clears things up. I guess I'd kind of consider "stashing" to be like a lightweight, nameless, branch. So anything stash can do, branch can as well but with more words. Nice!

Git Solutions


Solution 1 - Git

'stash' takes the uncommitted, "dirty" stuff on your working copy, and stashes it away, leaving you with a clean working copy.

It doesn't really branch at all. You can then apply the stash on top of any other branch. Or, as of Git 1.6, you can do:

git stash branch <branchname> [<stash>]

to apply the stash on top of a new branch, all in one command.

So, stash works great if you have not committed to the "wrong" branch yet.

If you've already committed, then the workflow you describe in your question is a better alternative. And by the way, you're right: Git is very flexible, and with that flexibility comes overlapping functionality.

Solution 2 - Git

When you restore your stash, your changes are reapplied and you continue working on your code.

To stash your current changes

$ git stash save 
Saved "WIP on master: e71813e..."

You can also have more than one stash. The stash works like a stack. Every time you save a new stash, it's put on top of the stack.

$ git stash list
stash@{0}: WIP on master: e71813e..."

Note the stash@{0} part? That's your stash ID. You'll need it to restore it later on. Let's do that right now. The stash ID changes with every stash you make. stash@{0} refers to the last stash you made.

To apply a stash

$ git stash apply stash@{0}

You may notice the stash is still there after you have applied it. You can drop it if you don't need it any more.

$ git stash drop stash@{0}

Or, because the stash acts like a stack, you can pop off the last stash you saved:

$ git stash pop

If you want to wipe all your stashes away, run the 'clear' command:

$ git stash clear

It may very well be that you don't use stashes that often. If you just want to quickly stash your changes to restore them later, you can leave out the stash ID.

$ git stash
...
$ git stash pop

Feel free to experiment with the stash before using it on some really important work.

I also have a more in-depth version of this posted on my blog.

Solution 3 - Git

I'm always wary of git stash. If you stash a few times, things tend to get messy. git stash list will display a numbered list of stashes you created, with messages if you provided them... But the problem lies in the fact that you can't clean up stashes except with a brutal git stash clear (which removes them all). So unless you're always consistently giving super-descriptive messages for your stashes (kinda goes against stash's philosophy), you end up with an incomprehensible bunch of stashes.

The only way I know of to figure out which one's which is to use gitk --all and spot the stashes. At least this lets you see what commit the stash was created on, as well as the diff of everything included in that stash.

Note that I'm using git 1.5.4.3, and I think 1.6 adds git stash pop, which I guess would apply the selected stash and remove it from the list. Which seems a lot cleaner.

For now, I always try to branch unless I'm absolutely positive I'm gonna get back to that stash in the same day, even within the hour.

Solution 4 - Git

If you look for a workflow that may be more fitting than git stash, you may want to look at [git-bottle][1]. It's a utility for the purpose of saving and restoring the various git working states as normal git commits, effectively snapshotting the current and pertinent state of your working tree and all various file states shown under git status.

Key differences from git stash:

  • git stash saves the dirty git state narrowly (modified files, and added files in the index), whereas git-bottle is designed to save everything that is different from HEAD, and it differentiates in a preserving way between modified, modified and not added, not added, unmerged paths, and the complete rebase/merge states (only paths under .gitignore are not saved).

  • git stash saves to stash objects that you need to keep track separately. If I stashed something 2 weeks ago I might not remember it, whereas git-bottle saves as tentative commits to the current branch. The reverse action is git-unbottle which is the equivalent of the git stash pop. It is possible to push and share these commits among repositories. This can be useful for remote builds, where you have another repository in a remote server just for building, or for collaborating with other people on conflict resolution.

    [1]: https://github.com/da-x/git-bottle "git-bottle"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWill RobertsonView Question on Stackoverflow
Solution 1 - GitJordi BunsterView Answer on Stackoverflow
Solution 2 - GitAriejanView Answer on Stackoverflow
Solution 3 - GitwebmatView Answer on Stackoverflow
Solution 4 - GitDan AloniView Answer on Stackoverflow