我经常使用gitstash和gitstashpop来保存和恢复工作树中的更改。昨天,我在我的工作树中做了一些修改,这些修改是我藏起来并弹出的,然后我对工作树做了更多的修改。我想回去回顾一下昨天隐藏的更改,但gitstashpop似乎删除了对相关提交的所有引用。

我知道如果我使用git stash,那么.git/refs/stash包含用于创建stash的提交的引用。git/logs/refs/stash包含整个存储。但这些参考资料在git stash pop之后就不见了。我知道提交仍在我的存储库中,但我不知道它是什么。

有没有一种简单的方法可以恢复昨天的存储提交引用?


当前回答

我喜欢亚里士多德的方法,但不喜欢使用GITK。。。因为我习惯于从命令行使用GIT。

相反,我接受了悬空提交,并将代码输出到DIFF文件,以便在代码编辑器中查看。

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

现在,您可以将生成的diff.txt文件(位于主文件夹中)加载到txt编辑器中,并查看实际代码和生成的SHA。

那就用

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

其他回答

一旦你知道你丢弃的隐藏提交的哈希值,你就可以将其作为一个隐藏:

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}'

…或使用PowerShell for Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $_.ToString().Split(" ")[2] }

这将在提交图的顶端显示所有提交,这些提交不再从任何分支或标记引用——每个丢失的提交,包括您创建的每个隐藏提交,都将位于该图的某个位置。

找到您想要的隐藏提交的最简单方法可能是将该列表传递给gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

…如果使用PowerShell for Windows,请查看emragins的答案。

这将启动一个存储库浏览器,显示存储库中的每一次提交,无论它是否可访问。

如果您更喜欢控制台上的图形而不是单独的GUI应用程序,那么可以用git-log-grap-online之类的东西来替换gitk。

要发现隐藏提交,请查找以下形式的提交消息:

某个分支上的WIP:commithash一些旧的提交消息

注意:如果您在执行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:6a9b2”(“work”是我的分支,619bb2是最近的提交)。

我注意到,如果我使用“git stash apply”而不是“git stash pop”,我就不会有这个问题,如果我用“git sash save message”,那么提交可能会更容易找到。

更新:根据内森的想法,这变得更短:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

只查看隐藏提交、它们附加的位置以及它们的内容

结果样本

Checking object directories: 100% (256/256), done.
2022-08-31 10:20:46 +0900 8d02f61 WIP on master: 243b594 add css
A       favicon.ico

命令

git fsck --dangling | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ct %h" | sort | awk '{print $2}' | { while read hash; do status=$(git stash show $hash --name-status 2>/dev/null); if (( $? == 0 )); then git show $hash -s --format="%C(green)%ci %C(yellow)%h %C(blue)%B"; echo "$status"; fi; done; }

若要查看完整哈希,请将%h更改为%h为了减少时间,尾部fsck类似于gitfsck--悬挂|tail-100|awk。。。

回收样品

使用gitk的Windows PowerShell等效程序:

gitk--all$(git fsck--no reflog |选择字符串“(悬空提交)(.*)”|%{$_.Line.Split('')[2]})

也许有一种更有效的方法可以在一个管道中完成这项工作,但这确实有效。

要查看终端中的提交,只有过滤我们关心的提交,我们才能使用:

git log --oneline --all --grep="^WIP on .*: [a-f0-9]\+" --grep="^On [^ ]*:" --grep="^index on [^ ]*:" $( env LANG=C git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

这是基于亚里斯多德·帕加尔茨的回答。