tags:

views:

1481

answers:

4

I'd like to know if it is possible to extract a single file or diff of a file from a git stash without popping the stash changeset off.

Might anyone be able to provide some suggestions/ideas about this?

A: 

You can get the diff for a stash with "git show stash@{0}" (or whatever the number of the stash is; see "git stash list"). It's easy to extract the section of the diff for a single file.

Nathan Kitchen
+2  A: 

If you use git stash apply rather than git stash pop, it will apply the stash to your working tree but still keep the stash.

With this done, you can add/commit the file that you want and then reset the remaining changes.

Tim Henigan
+21  A: 

In git stash manpage you can read that (in "Discussion" section, just after "Options" description):

A stash is represented as a commit whose tree records the state of the working directory, and its first parent is the commit at HEAD when the stash was created.

So you can treat stash (e.g. stash@{0} is first / topmost stash) as a merge commit, and use:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Explanation: stash@{0}^1 shortcut means first parent of given stash, which as stated in explanation above is commit at which changes were stashed away. We use this form of "git diff" (with two commits) because stash@{0} / refs/stash is a merge commit, and we have to tell git which parent we diff againts. More cryptic:

$ git diff stash@{0}^! -- <filename>

should also work (see git rev-parse manpage for explanation of rev^! syntax, in "Specifying ranges" section).

Likewise, you can use git checkout to check a single file out of the stash:

$ git checkout stash@{0} -- <filename>

or to save it under another filename:

$ git show stash@{0}:<full filename>  >  <newfile>

(note that here <full filename> is full pathname of a file relative to top directory of a project (think: relative to stash@{0})).

Jakub Narębski
This is pretty cool... I didn't _really_ understand how stash worked until I read your answer (which lead me to the git-checkout addition). I really didn't get that, when you do a stash, git saves TWO commits -- one for the state of the index and one for the state of the working copy which is a merge between the index and the original HEAD. This explains the odd trees I've seen when I visualize the repository with "gitk --all" when stashes are present.
Pat Notz
Mostly I find the git checkout application to be the best way to accomplish what it is I wanted to do. However I was curious and double-checked `git checkout`'s man page. It cannot drop the file into another location. There is a reference to this in: http://stackoverflow.com/questions/888414/git-checkout-older-revision-of-a-file-under-a-new-name/888623#888623
Danny
One hell of a complete answer. Thanks!
Danny
$ git checkout stash@{0} -- <filename> is very useful, thanks
Brandon Thomson
A: 

The simplest concept to understand, although maybe not the best, is you have three files changed and you want to stash one file.

If you do git stash to stash them all, git stash apply to bring them back again and then git checkout f.c on the file in question to effectively reset it.

When you want to unstash that file run do a git reset --hard and then run git stash apply again, taking advantage ofthe fact that git stash apply doesn't clear the diff from the stash stack.

Philluminati