Is it possible to extract a single file or diff of a file from a git stash without popping the stash changeset off?
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, 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>
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}'
.
git checkout
's man page. It cannot drop the file into another location. There is a reference to this in: #888914 –
Physic 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). –
Saudra 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. –
Whitefish git diff stash@{0}^1 stash@{0} -- <filename> | patch -p1
–
Beccafico git checkout stash@{0} -- <path-to-folder>
can checkout folders too! –
Repent patch -p1
. I had tried git diff … | git apply
from https://mcmap.net/q/41250/-how-to-unstash-only-certain-files, but that failed with the error "patch does not apply." I tried git diff … | patch -p1
instead and it applied the diff from the stash perfectly! –
Saudra git checkout stash -- <filename>
without the '@{0}' after 'stash'. (It might work with multiple stashed states, too, but I have not tried it and do not know which state would be the default.) –
York @{0}
–
Acedia $ git checkout stash@{0} -- <filename>
stages the file for commit. Can that be avoided as quite often file is taken from stash just for tests? –
Exequatur $ git restore --worktree --source=stash@{0} -- <filename>
, I think. –
Interradial stash@{0}
to single quotes or backticks. Thats because curly braces have special meaning in PowerShell. Otherwise you'll get error: unknown switch `e'
. –
Construct checkout
which does not find untracked files apparently –
Erichericha --include-utracked
, then the tree with untracked files is available as stash@{0}^2
, that is second parent of stash (so you can for example use git checkout 'stash@{0}^2' -- <filename>
). You can see this with git log --graph --oneline stash
. –
Interradial git show 'stash@{0}^2':<filename>
(and try git ls-tree -r 'stash@{0}^2'
to check if file name is correct). –
Interradial $ git checkout stash@{0} -- <filename>
Notes:
Make sure you put space after the "--" and the file name parameter
Replace zero(0) with your specific stash number. To get stash list, use:
git stash list
Based on Jakub Narębski's answer -- Shorter version
git checkout stash^{/'Stash name here'} -- <filename>
–
Outsole 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. –
Saudra git restore --source=stash@{0} -- <filename>
–
Pisistratus 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.
git stash pop stash@{0}
(list the stashed changes: git stash list
) –
Deviant 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
.
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 e
dit the patch). Path alone will overwrite the file, like I wrote, "all changes". –
Chromous 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. –
Bipod Short answer
To see the whole file: git show stash@{0}:<filename>
To see the diff: git diff stash@{0}^1 stash@{0} -- <filename>
diff
with difftool
to use your favourite external diff. –
Sparks 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.
error: No valid patches in input (allow with "--allow-empty")
–
Thant 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.
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
. –
Mating 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.
For VS Code users, there is one method. Make sure to have GitLens extension installed.
- Go on
SOURCE CONTROL
tab - Click on
STASHES
. - You will be able to see available stashes.
- Click on the desired stash.
- Right click on the desired file which you want to unstash.
- You will get 2 options,
Apply Changes
andRestore (Checkout)
. You can click any of the options and you will get your file underChanges
if you chooseApply Changes
orStaged Changes
if you chooseRestore (Checkout)
.
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.
© 2022 - 2024 — McMap. All rights reserved.