我经常使用git stash
和git stash pop
来保存和恢复我工作树上的修改。昨天我在工作树上有一些改动,我把它们藏起来并弹出,然后我在工作树上做了更多改动。我想回过头来看看昨天隐藏的修改,但git stash pop
似乎会删除所有相关提交的引用。
我知道,如果我使用git stash
,那么.git/refs/stash包含用于创建储藏的提交的引用。而.git/logs/refs/stash 包含整个储藏库。但在git stash pop
之后,这些引用就消失了。我知道提交的内容还在我的版本库中,但我不知道它是什么。
有什么简单的方法可以恢复昨天的储藏库提交参考吗?
请注意,这对今天的我来说并不重要,因为我每天都有备份,可以回到昨天的工作树上获取我的修改。我问这个问题是因为一定有一个更简单的方法。
一旦你知道了你丢弃的藏品的哈希值,你就可以把它作为一个藏品来应用。
git stash apply $stash_hash
或者,你可以为它创建一个单独的分支,用
git branch recovered $stash_hash
之后,你可以用所有正常的工具做你想做的事。当你完成后,就把这个分支吹走吧。
如果你只是刚刚弹出,并且终端仍然打开,你会屏幕上仍然有git stash pop
打印的哈希值(谢谢,Dolda)。
否则,你可以用这个在Linux、Unix或Windows的Git Bash中找到它。
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
...或者使用Windows的Powershell。
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
这将显示你的提交图中所有不再被任何分支或标签引用的提交--每一个丢失的提交,包括你曾经创建的每一个缓存提交,都会出现在该图中。
找到你想要的缓存提交的最简单方法可能是将该列表传递给 gitk
。
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
...或者如果使用Windows的Powershell,请看emragins的答案。
这将启动一个版本库浏览器,显示版本库中*所有的提交,不管它是否可达。
如果你喜欢在控制台看到漂亮的图表,而不是单独的GUI应用程序,你可以用git log --graph --oneline --decorate
来代替gitk
。
要发现储藏室的提交,可以寻找这种形式的提交信息。
WIP on somebranch: commithash Some old commit message
注意。如果你在做`git stash'时没有提供信息,那么提交信息将只以这种形式出现(以"WIP on"开头)。
我刚刚构建了一个命令,帮助我找到了我丢失的藏品提交。
for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less
这条命令列出了 .git/objects 树中的所有对象,找到了属于 commit 类型的对象,然后显示了每个对象的摘要。从这一点上看,只需在提交中找到合适的"WIP on work。6a9bb2"("work"是我的分支,619bb2是最近的一个提交)。
我注意到,如果我用"git stash apply"而不是"git stash pop"就不会有这个问题,如果我用"git stash save message",那么提交可能更容易找到。
更新:有了Nathan'的想法,这变得更短了。
for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
git fsck --unreachable | grep commit
应该会显示sha1,尽管它返回的列表可能相当大。git show <sha1>
会显示是否是你想要的提交。
git cherry-pick -m 1 <sha1>
将把该提交合并到当前分支。