我经常使用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或Git Bash for Windows中找到它:
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
...或者使用Powershell for Windows:
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}' )
...或者如果使用Powershell for Windows,请查看emragins的答案.
这将启动一个存储库浏览器,显示存储库中的每个提交,无论它是否可访问.
如果您喜欢在控制台上通过单独的GUI应用程序使用漂亮的图形,则可以替换gitk
它git log --graph --oneline --decorate
.
要查找存储提交,请查找此表单的提交消息:
在somebranch上的 WIP :commithash一些旧的提交消息
注意:如果您没有提供消息,则提交消息将仅以此形式(以"WIP on"开头)git stash
.
如果您没有关闭终端,只需查看输出git stash pop
,您将获得已删除存储的对象ID.它通常看起来像这样:
$ git stash pop [...] Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
(注意,git stash drop
也会生成相同的行.)
为了获得那些存储,只需运行git branch tmp 2cae03e
,你就可以将它作为一个分支.要将其转换为存储,请运行:
git stash apply tmp git stash
将它作为分支也允许您自由地操纵它; 例如,樱桃挑选或合并它.
只是想提到对已接受的解决方案的这一补充.我第一次尝试这种方法时并不是很明显(也许应该是这样),但是要从哈希值中应用存储,只需使用"git stash apply":
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
当我刚接触git时,这对我来说并不清楚,我正在尝试"git show","git apply","patch"等的不同组合.
要获取仍在存储库中但不再可访问的存储列表:
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
如果您为藏匿物提供了标题,请将-grep=WIP
命令末尾的"WIP"替换为消息的一部分,例如-grep=Tesselation
.
该命令正在为"WIP"进行grepping,因为存储的默认提交消息在表单中 WIP on mybranch: [previous-commit-hash] Message of the previous commit.
我刚刚构建了一个命令,帮助我找到丢失的存储提交:
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 ",那么提交可能更容易找到.
更新:根据内森的想法,这变得更短:
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
将显示它是否是您想要的提交.
git cherry-pick -m 1
将提交合并到当前分支.
如果你想要重建一个丢失的存储,你需要先找到丢失的存储的哈希值.
正如亚里士多德Pagaltzis所建议的,git fsck
应该帮助你.
就个人而言,我使用我的log-all
别名向我展示每次提交(可恢复的提交)以更好地了解情况:
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
如果您只查看"WIP on"消息,则可以进行更快速的搜索.
一旦你知道你的sha1,你只需更改你的存储reflog以添加旧的存储:
git update-ref refs/stash ed6721d
你可能更愿意有一个相关的消息,所以a -m
git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d
你甚至想用它作为别名:
restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
使用gitk等效的Windows PowerShell:
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })
可能有一种更有效的方法在一个管道中执行此操作,但这可以完成这项工作.
我喜欢亚里士多德的方法,但不喜欢使用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 fsck --unreachable
检查无法访问的提交哈希 -
git show hash
如果你发现藏匿物品,最后申请 -
git stash apply hash
在使用git v2.6.4的OSX中,我只是意外地运行了git stash drop,然后我通过下面的步骤找到了它
如果您知道藏匿名称,请使用:
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2
否则你将通过手动找到结果中的ID:
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show
然后,当你发现commit-id刚刚点击git stash时,应用{commit-id}
希望这可以帮助别人
为什么人们会问这个问题?因为他们还不了解或了解reflog.
这个问题的大多数答案给出了长命令,几乎没有人会记得.所以人们进入这个问题并复制粘贴他们认为他们需要的东西并且几乎立即忘记它.
我会建议所有人用这个问题来检查reflog(git reflog),不仅如此.一旦你看到所有提交的列表,有一百种方法可以找出你正在寻找的提交,并挑选它或从中创建一个分支.在这个过程中,您将了解各种基本git命令的reflog和有用选项.
我想添加到已接受的解决方案另一个好方法来完成所有更改,当你没有gitk可用或没有X输出时.
git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits for h in `cat tmp_commits`; do git show $h | less; done
然后你会得到一个接一个显示的哈希的所有差异.按'q'进入下一个差异.
我无法在一个简单的命令窗口(在我的例子中是Windows 7)中获得在Windows上工作的任何答案.awk
,grep
并Select-string
没有被识别为命令.所以我尝试了一种不同的方法:
第一次运行: git fsck --unreachable | findstr "commit"
将输出复制到记事本
找到替换"无法访问提交" start cmd /k git show
看起来像这样:
start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4
start cmd /k git show 44078733e1b36962571019126243782421fcd8ae
start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1
start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e
另存为.bat文件并运行它
该脚本将打开一堆命令窗口,显示每个提交
如果你找到了你正在寻找的那个,请运行: git stash apply (your hash)
可能不是最好的解决方案,但对我有用
亚里士多德接受的答案将显示所有可达的提交,包括非类似stash的提交.滤除噪音:
git fsck --no-reflog | \ awk '/dangling commit/ {print $3}' | \ xargs git log --no-walk --format="%H" \ --grep="WIP on" --min-parents=3 --max-parents=3
这将只包括具有3个父提交(存储将具有)的提交,并且其消息包括"WIP on".
请记住,如果您使用消息(例如git stash save "My newly created stash"
)保存了存储,则会覆盖默认的"WIP on ..."消息.
您可以显示有关每个提交的更多信息,例如显示提交消息,或将其传递给git stash show
:
git fsck --no-reflog | \ awk '/dangling commit/ {print $3}' | \ xargs git log --no-walk --format="%H" \ --grep="WIP on" --min-parents=3 --max-parents=3 | \ xargs -n1 -I '{}' bash -c "\ git log -1 --format=medium --color=always '{}'; echo; \ git stash show --color=always '{}'; echo; echo" | \ less -R