How to recover a dropped stash in Git?
I frequently use git stash
and git stash pop
to save and restore changes in my working tree. Yesterday I had some changes in my working tree that I had stashed and popped, and then I made more changes to my working tree. I'd like to go back and review yesterday's stashed changes, but git stash pop
appears to remove all references to the associated commit.
I know that if I use git stash
then .git/refs/stash contains the reference of the commit used to create the stash. And .git/logs/refs/stash contains the whole stash. But those references are gone after git stash pop
. I know that the commit is still in my repository somewhere, but I don't know what it was.
Is there an easy way to recover yesterday's stash commit reference?
Note that this isn't critical for me today because I have daily backups and can go back to yesterday's working tree to get my changes. I'm asking because there must be an easier way!
If you have only just popped it and the terminal is still open, you will still have the hash value printed by git stash pop
on screen (thanks, Dolda).
Otherwise, you can find it using this for Linux and Unix:
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
and for Windows:
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
This will show you all the commits at the tips of your commit graph which are no longer referenced from any branch or tag – every lost commit, including every stash commit you've ever created, will be somewhere in that graph.
The easiest way to find the stash commit you want is probably to pass that list to gitk
:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
This will launch a repository browser showing you every single commit in the repository ever, regardless of whether it is reachable or not.
You can replace gitk
there with something like git log --graph --oneline --decorate
if you prefer a nice graph on the console over a separate GUI app.
To spot stash commits, look for commit messages of this form:
WIP on somebranch: commithash Some old commit message
Note: The commit message will only be in this form (starting with "WIP on") if you did not supply a message when you did git stash
.
Once you know the hash of the commit you want, you can apply it as a stash:
git stash apply $stash_hash
Or you can use the context menu in gitk
to create branches for any unreachable commits you are interested in. After that, you can do whatever you want with them with all the normal tools. When you're done, just blow those branches away again.
If you didn't close the terminal, just look at the output from git stash pop
and you'll have the object ID of the dropped stash. It normally looks like this:
$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
(Note that git stash drop
also produces the same line.)
To get that stash back, just run git branch tmp 2cae03e
, and you'll get it as a branch. To convert this to a stash, run:
git stash apply tmp
git stash
Having it as a branch also allows you to manipulate it freely; for example, to cherry-pick it or merge it.
Just wanted to mention this addition to the accepted solution. It wasn't immediately obvious to me the first time I tried this method (maybe it should have been), but to apply the stash from the hash value, just use "git stash apply ":
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
When I was new to git, this wasn't clear to me, and I was trying different combinations of "git show", "git apply", "patch", etc.
链接地址: http://www.djcxy.com/p/4012.html上一篇: 如何停止跟踪并忽略Git中文件的更改?
下一篇: 如何恢复Git中丢失的存储?