1163

Is it possible to extract a single file or diff of a file from a git stash without popping the stash changeset off?

10 Answers 10

1621

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

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 means the first parent of the given stash, which as stated in the explanation above is the 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 want to diff against. 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, to answer your question, you can use git checkout to check a single file out of the stash (note that this will not merge the stash like git stash apply does—that means any changes made to the file will be overwritten):

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

or to save it under another filename:

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

or

$ git show stash@{0}:./<relative 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})).


You might need to protect stash@{0} from shell expansion, i.e. use "stash@{0}" or 'stash@{0}'.

21
  • 19
    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
    Commented Jul 9, 2009 at 20:56
  • 6
    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: stackoverflow.com/questions/888414/…
    – Danny
    Commented Jul 9, 2009 at 22:15
  • 73
    Note that the git checkout approach copies the exact file from the stash -- it doesn't merge it with what's in your working directory like git stash apply would. (So if you have any changes from the base the stash was created on, they'll be lost).
    – peterflynn
    Commented Apr 5, 2013 at 22:04
  • 6
    Note that in order for git stash apply to merge the changes in a file that has been modified in the work tree since the file was stashed, that file in the work tree must be staged. For auto-merge to work, the same files cannot be modified both in the working copy and in the stashed copy-to-be-merged. Finally, stash apply doesn't remove the item from stash like git stash pop would.
    – Ville
    Commented Nov 4, 2013 at 16:15
  • 6
    git diff stash@{0}^1 stash@{0} -- <filename> | patch -p1
    – isaaclw
    Commented Oct 31, 2014 at 1:42
110
git checkout stash@{0} -- <filename>

Notes:

  1. Warning: this will not merge the file—any existing changes to the file will be overwritten.

  2. Make sure you put spaces around the --.

  3. If the stash you want the file from isn't the latest one, replace 0 with your specific stash number. (To list stashes, run git stash list.)

Based on Jakub Narębski's answer -- Shorter version

3
  • 1
    You can also use the stash name git checkout stash^{/'Stash name here'} -- <filename> Commented Feb 10, 2021 at 16:50
  • 4
    This has two risks: (a) it will silently overwrite any unstaged local changes you have in this file; and (b) it copies the exact file from the stash, without merging it with any changes that have been made on your branch since the stash was saved. That may be confusing since git stash apply / pop don't have either of those pitfalls. To get behavior that is more expected, use one of the git diff-based approaches in some of the other answers here.
    – peterflynn
    Commented Jun 22, 2022 at 20:06
  • 2
    Modern git versions: use git restore --source=stash@{0} -- <filename>
    – jII
    Commented Oct 10, 2023 at 15:52
95

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.

3
  • 4
    To pop a specific stash: git stash pop stash@{0} (list the stashed changes: git stash list)
    – MrYoshiji
    Commented Jan 15, 2015 at 16:53
  • If other files in the stash cause a merge conflict, git doesn't let me commit on the file I want :( Commented Dec 7, 2019 at 23:45
  • 4
    This is the best answer. You don't have to use a different command (heh) to do what git stash apply should do, and you don't have to worry about any weird side effects (git checkout copies the exact file to the stash) or memorize any weird syntax.
    – Patrick
    Commented May 25, 2022 at 21:40
50

Edit: See cambunctious's answer, which is basically what I now prefer because it only uses the changes in the stash, rather than comparing them to your current state. This makes the operation additive, with much less chance of undoing work done since the stash was created.

To do it interactively, you would first do

git diff stash^! -- path/to/relevant/file/in/stash.ext perhaps/another/file.ext > my.patch

...then open the patch file in a text editor, alter as required, then do

git apply < my.patch

cambunctious's answer bypasses the interactivity by piping one command directly to the other, which is fine if you know you want all changes from the stash. You can edit the stash^! to be any commit range that has the cumulative changes you want (but check over the output of the diff first).

If applying the patch/diff fails, you can change the last command to git apply --reject which makes all the changes it can, and leaves .rej files where there are conflicts it can't resolve. The .rej files can then be applied using wiggle, like so:

wiggle --replace path/to/relevant/file/in/stash.ext{,.rej}

This will either resolve the conflict, or give you conflict markers that you'd get from a merge.

If your distro doesn't have wiggle, you can just build it:

cd /usr/local/src/
git clone git://git.neil.brown.name/wiggle
cd wiggle/
git checkout v1.3
make install

Previous solution: There is an easy way to get changes from any branch, including stashes:

$ git checkout --patch stash@{0} path/to/file

You may omit the file spec if you want to patch in many parts. Or omit patch (but not the path) to get all changes to a single file. Replace 0 with the stash number from git stash list, if you have more than one. Note that this is like diff, and offers to apply all differences between the branches. To get changes from only a single commit/stash, have a look at git cherry-pick --no-commit.

3
  • 1
    Does this copy the exact file from the stash, or does it merge? In case of copy, if you have any changes since the stash was created, they will be lost.
    – Danijel
    Commented Oct 30, 2018 at 11:39
  • 3
    @Danijel Read git help checkout. --patch does interactive merging, It applies whatever hunk(s) you approve in the shell (or whatever you save if you choose to edit the patch). Path alone will overwrite the file, like I wrote, "all changes".
    – Walf
    Commented Oct 31, 2018 at 6:45
  • 1
    slight improvement: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' -- then doing git applydiffat stash@{4} only uses files that changed between the stash and its parent.
    – Mark
    Commented May 8, 2020 at 18:38
39

Short answer

To see the whole file: git show stash@{0}:<filename>

To see the diff: git diff stash@{0}^1 stash@{0} -- <filename>

3
  • 1
    I don't think s/he was concerned with viewing the stash for a particular file--only popping that file.
    – Alkanshel
    Commented Apr 1, 2016 at 18:29
  • 3
    This is what I was looking for. Then you can replace diff with difftool to use your favourite external diff.
    – Peet Brits
    Commented Jan 17, 2017 at 10:36
  • 2
    My git repo was corrupted but I had stashed the files, but couldn't apply because of the corruption. I was able to use this and pipe to a new file, diff it, and I was good to go. Thank you! Commented Nov 24, 2020 at 21:16
21

Use the following to apply the changes to a file in a stash to your working tree.

git diff stash^! -- <filename> | git apply

This is generally better than using git checkout because you won't lose any changes you made to file since you created the stash.

2
  • 1
    it is showing me this error: error: No valid patches in input (allow with "--allow-empty") Commented Mar 1 at 9:17
  • @user8395964 that means there are no changes to be applied (or the changes in the stash have already been applied) Commented Mar 5 at 23:23
11

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.

1
  • 6
    Simpler still for minds like me: use git show stash to show the topmost stash (normally the only one you have). Similarly you can show the diff between your current branch and the stash with git diff head stash.
    – Dizzley
    Commented Nov 2, 2013 at 10:00
6

For VS Code users, there is one method. Make sure to have GitLens extension installed.

  1. Go on SOURCE CONTROL tab
  2. Click on STASHES.
  3. You will be able to see available stashes.
  4. Click on the desired stash.
  5. Right click on the desired file which you want to unstash.
  6. You will get 2 options, Apply Changes and Restore (Checkout). You can click any of the options and you will get your file under Changes if you choose Apply Changes or Staged Changes if you choose Restore (Checkout).

unstash files from stash

5

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.

1

If the stashed files need to merge with the current version so use the previous ways using diff. Otherwise you might use git pop for unstashing them, git add fileWantToKeep for staging your file, and do a git stash save --keep-index, for stashing everything except what is on stage. Remember that the difference of this way with the previous ones is that it "pops" the file from stash. The previous answers keep it git checkout stash@{0} -- <filename> so it goes according to your needs.

Not the answer you're looking for? Browse other questions tagged or ask your own question.