This question had the same title but it is NOT the same question. That question is really asking \"Discard results of git stash pop\". This question is actually
You can reverse patch the stash (which as already mentioned should still be there as git wont drop a stash if it doesn't apply cleanly)
git stash show -p stash@{0} | git apply -R
Greg Hewgill's answer is right (and upvoted, and the OP should accept it) but there's are several additional caveats here, in case anyone wants to use the answer in a more general fashion. Let's look first at the specific sequence of commands used:
git stash git checkout bar git stash pop # ERROR ... lots of conflicts
Now, let's list the caveats:
git stash pop
has failed. (Greg already noted this.)git stash --keep-index
when creating the stash.git stash
, you made no changes to your work-tree.git checkout
command succeeded, so it may have made changes to your work-tree—in fact, it must have done so for the pop
to fail—but your work-tree is still "clean", as git status
would say.It's this last point, that git status
would (before the attempt to git stash pop
) tell you that your work-tree is clean
, that is the key. Had you made changes to your work-tree, either before or after git checkout bar
, you would be in more trouble.
Because you did not do those things, git reset --hard
is the answer.
What git stash
does, in general, is make two commits. One saves the current index and the other saves the current work-tree.1 These commits are slightly special in a few ways; the most important is that they are on no branch at all.2 Having made its commits, git stash
then normally runs git reset --hard
.3
What the git reset --hard
step does is to make the index and work-tree match the current commit. That is, we've saved the (whole) index and (the entire tracked part of the) work-tree in the stash; so whatever is different between the current HEAD
commit and the index, can be re-set to be the same again; and whatever is different between the HEAD
commit and the work-tree, can be re-set to be the same again.
After the git reset
, both the index and work-tree are "clean", as git status
will say: they both match the HEAD
commit. You can then git checkout
other branches, as you have no unsaved work. You can then attempt to git stash apply
, or even git stash pop
, to "move" your changes to this other branch.
When that fails—as in this case—the stash remains in the saved stashes. The current index and work-tree are now full of merge conflicts. If you run git reset --hard
, Git will re-set the index and work-tree to match the HEAD
commit as usual, so that you'll be back to the same situation you were in after the git checkout
step. Since you had no unsaved work (your saved work is still in the stash commits), you're OK here.
(If you did have unsaved work, the git stash apply
step will have mangled that unsaved work by attempting to merge the stashed work-tree changes. This is very difficult to undo, in general.)
1While git stash
typically makes two commits, if you run it with --all
or --include-untracked
, it will make three commits. I like to call these the i
(index), w
(work-tree), and u
(untracke files) commits.
When using --all
or --include-untracked
, the save
or push
step will do more than just git reset --hard
: it will also run git clean
to remove whatever went into the third commit (untracked-only files, or untracked-including-ignored files). You may have to repeat this git clean
work before applying such a stash, which is tricky and annoying.
Later, when you run git stash apply
, Git will (try to) apply the u
commit if it exists. It will always (try to) apply the w
commit. It will (try to) apply the i
commit only if you give it the --index
flag. There are some minor bugs in many versions of git stash
surrounding this whole "separate index restoration" stuff. They tend to affect people who want to use the --keep-index
and --index
flags in, e.g., pre-commit hooks.
Note that git stash pop
is just git stash apply && git stash drop
: that is, attempt to apply the stash, and then, if Git thinks the apply
went well, also drop
the stash. I find it better to use git stash apply
first, to avoid dropping the stash even if Git thinks it went well, because Git and I sometimes disagree as to what "went well" means. :-)
2Git uses the name refs/stash
to remember the current stash, and (ab)uses the reflog for refs/stash
to maintain the remainder of the "stash stack". Branch names internally all have the form refs/heads/name
, so refs/stash
is not a branch name.
3If you use git stash --keep-index
, it runs more than just git reset --hard
: it extracts the saved index state to the work-tree. The goal here is to leave the work-tree set up the way the index was set up, so that you can test what you were about to commit. As noted in footnote 1, there's a small but fairly nasty bug here with many versions of git stash
, where the stashed work-tree state accidentally takes the index version instead of the work-tree version if the correct work-tree version matches the HEAD
version.
So, I'm not 100% sure of the answer in all cases. In my case when I typed git stash pop
and I was on branch bar
there were conflicts. So while it applied the stash it didn't drop the stash. So to undo and correctly apply the stash to branch foo
it was just
git reset --hard # resets bar to before the stash pop
git checkout -b foo
git stash pop
If there had been no conflicts with branch bar
then it's just
git stash # restash
git checkout -b foo
git stash pop
In your example, to restore to the state before git stash pop
, use:
git reset --hard bar
This form of the git reset
command restores the state of the index and the working directory to the head of the bar
branch.
Because you had conflicts on the first git stash pop
, the stash remains on the top of the stash stack.
From there, you can git checkout foo
and git stash pop
again.