1

I am surprised not having found a response to this question but basically say I have a stash with several files in it (I can explore it through git extension for instance). Looking at its content, I'd like to drop some files before applying it, is it possible?

The only workaround I can think of is:

  1. checkout the stash to a new branch
  2. checkout the targeted files
  3. stash again
  4. delete the branch

Is there something better?

ClementWalter
  • 4,814
  • 1
  • 32
  • 54

4 Answers4

4

You can directly use stash (or stash@{0}) as a commit reference.

If your working tree is clean (no modified files), you can checkout the files you want :

git checkout stash -- file1 file2 file3

and then inspect the diff manually to keep what you want.


If you want something closer to the behaviour of git stash apply, you can create a patch and apply it :

git show -p stash -- file1 file2 file3 | git apply -

[EDIT] To list the files modified in stash :

git diff --name-only stash^ stash

If you want to get all files except one :

git show -p stash -- $(git diff --name-only stash^ stash | grep -v "thefile")
LeGEC
  • 46,477
  • 5
  • 57
  • 104
  • git is amazing thanks. This is great for what it does, but does not modify the stash. Say I want to apply all but one file, I have to list them all. Is there some sort of opposite command ? – ClementWalter May 03 '17 at 09:06
  • I can't make `git show -p stash@{0} -- file1 file2 file3 | git apply - ` work, I got "error: unrecognized input" while it works without the `| git apply -` – ClementWalter May 03 '17 at 09:22
  • "It works" : do you mean that `git show -p ... > patch && git apply patch` works ? – LeGEC May 03 '17 at 10:25
1

Yes there is a better way to do it.

First of all, You can check the stash list as

git stash list

Then you can do below for checking contents of the stashed commits.

git stash show -p stash@{1}

Then you can apply using

git stash apply stash@{1}
FallAndLearn
  • 4,035
  • 1
  • 18
  • 24
  • thanks but this does not answer my question. I knew how to see the content of a stash and apply it globally. I was looking for sort of partial apply of a stash, see @LeGEC answer – ClementWalter May 03 '17 at 09:04
1

It seems like the tricky part of this question revolves around what you want the stash to look like when you're done. Since git stash {pop|apply} only affects the working tree (and sometimes index), it's easy enough to selectively take changes from a stash (enough so that I initially thought you were over-thinking the problem):

git stash pop
# maybe a 'git reset head' if the index was changed
git checkout -- file.with.unwanted.changes.in.stash

But those commands remove the stash entirely; and by contrast if I'd said git stash apply instead of pop, that leaves the stash unchanged. It sounds like you want the stash to remain with the changes you've selected (in case you should need to apply them again).

(I suppose alternately there could be times you'd want exactly the opposite - to leave in the stash those changes that you didn't apply, so they can be applied later.)

So taking a step back: what is involved in modifying a stash?

A stash, really, comprises two or three temporary commits. The special ref stash points to these commits, and a "stack" of multiple stashes is maintained using the reflog (which may be a bit of a hack, but generally is effective).

So to modify the stash is to create new commits (because commits are immutable) and rearrange the stash ref and reflog accordingly.

This is why the notations LeGEC mentions will work and may give you extra flexibility in reading a stash. But because the reflog usage is not the same as for non-stash refs, leveraging this fact to contrive a way to write to a stash could have unexpected results. I'm not saying the results would be horrible, or impossible to predict/control; but I think in the end you'd create more complexity than you'd avoid.

So if we confine ourselves to actual documented git-stash subcommands, then a stash is more or less atomic. When you create a stash there's a patch mode that lets you select working changes to put in the stack, but I'm aware of no corresponding functionality for pop/apply. Still, that's something:

If you have a clean work tree and a stash you want to split, you could try things like:

Apply some changes, and keep those same changes in the stash

git stash pop
git stash -p
# select the "good" changes
git checkout -- .
git stash apply

Apply some changes, and keep the remaining changes in the stash

git stash pop
git stash -p
# select the "unwanted" changes

Split the stash into two parts, decide what to do with them later

git stash pop
git stash -p
# select the "good" changes
git stash
# now the "good" changes are stash@{1} and the "unwanted" are stash@{0}
Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • Minor technical note: each stash is always at least two commits (index state plus work-tree state) and sometimes three: index, work-tree, and "additional". The "additional" part is present in `git stash -u` or `git stash -a` stashes and contains the "untracked-sans-ignored" or "untracked-including-ignored" files (only; this is unlike index and work-tree states, which both save all tracked files). – torek May 03 '17 at 17:54
  • @torek - Huh... for some reason I thought if one or the other were empty it would be omitted. Will update. Thanks. – Mark Adelsberger May 03 '17 at 18:02
1

Simple solution to remove a stash entry without applying it is to drop it:

git stash drop stash@{1}

Here 1 is the stash entry that you get by running:

git stash list
YetAnotherBot
  • 1,937
  • 2
  • 25
  • 32