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
in other words
// in branch foo
git stash
git checkout bar
git stash pop # ERROR. I didn't want to pop on top of bar, lots of conflicts
git stash undo-pop # NEED COMMAND TO PUT STASH AND LOCAL FILES BACK AS THEY WERE
git checkout foo
git stash pop
Is there a way to get everything back to the state just before I typed git stash pop
? In other words to actually UNDO the pop and put the stashed stuff back into the stash and put the local files back in the state they were before I typed git stash pop.
This is also not a dupe of How to recover a dropped stash in Git? Although that might be helpful in certain situations
We can use the reset command with some options to git undo failed stash pop. The git reset has recently learned the --merge option. The --merge option is like the default --mixed option, but it only applies to the files affected by the merge operation.
You need to resolve the conflicts by hand and call git stash drop manually afterwards. This will revert your local repo to the last commit. You should be able to push all of your commits (since the last push) without issue. If it does not work, then post the results back to your previous question).
To undo a git stash , use the git stash pop command. It will re-apply your stash to your working copy.
The stash entry is kept in case you need it again. There's no magic remedy for such merge conflicts. The only option for developers is to edit the file by hand and keep what they want and dispose of what they don't want. Once they merge and save the file, they will have effectively resolved the git stash conflict.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With