如何在 Git 中恢复丢失的存储?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/89332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to recover a dropped stash in Git?
提问by Greg Hewgill
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.
我经常使用git stash
和git stash pop
来保存和恢复我的工作树中的更改。昨天我对我的工作树进行了一些更改,这些更改被我隐藏和弹出,然后我对我的工作树进行了更多更改。我想回去查看昨天的隐藏更改,但git stash pop
似乎删除了对相关提交的所有引用。
I know that if I use git stash
then .git/refs/stash containsthe reference of the commit used to create the stash. And .git/logs/refs/stash containsthe 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.
我知道,如果我用git stash
那么git的/裁判/藏匿包含的参考提交用于创建藏匿。和git的/日志/裁判/藏匿包含了整个藏匿。但是那些参考文献已经消失了git stash pop
。我知道提交仍在我的存储库中的某个地方,但我不知道它是什么。
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!
请注意,这对我今天来说并不重要,因为我每天都有备份,并且可以返回到昨天的工作树来获取我的更改。我问是因为必须有更简单的方法!
回答by Aristotle Pagaltzis
Once you know the hash of the stash commit you dropped, you can apply it as a stash:
一旦您知道您删除的存储提交的哈希值,您就可以将其应用为存储:
git stash apply $stash_hash
Or, you can create a separate branch for it with
或者,您可以为它创建一个单独的分支
git branch recovered $stash_hash
After that, you can do whatever you want with all the normal tools. When you're done, just blow the branch away.
之后,您可以使用所有普通工具为所欲为。完成后,只需将树枝吹走即可。
Finding the hash
寻找哈希
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).
如果你刚刚弹出它并且终端仍然打开,你仍然会git stash pop
在屏幕上打印哈希值(谢谢,Dolda)。
Otherwise, you can find it using this for Linux, Unix or Git Bash for Windows:
否则,您可以在 Linux、Unix 或 Git Bash for Windows 上使用它来找到它:
git fsck --no-reflog | awk '/dangling commit/ {print }'
...or using Powershell for Windows:
...或使用 Windows 的 Powershell:
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
:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print }' )
...or see the answer from emraginsif using Powershell for Windows.
...或者如果使用 Windows 的 Powershell,请参阅emragins 的答案。
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.
如果您更喜欢控制台上的漂亮图形而不是单独的 GUI 应用程序,您可以将其替换gitk
为类似的内容git log --graph --oneline --decorate
。
To spot stash commits, look for commit messages of this form:
要发现 stash 提交,请查找以下形式的提交消息:
WIP on somebranch: commithash Some old commit message
somebranch 上的 WIP :commithash 一些旧的提交消息
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
.
注意:如果您在执行时未提供消息,则提交消息将仅采用此形式(以“WIP on”开头)git stash
。
回答by Dolda2000
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
,您就会拥有已丢弃存储的对象 ID。它通常看起来像这样:
$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
(Note that git stash drop
also produces the same line.)
(请注意,这git stash drop
也会产生相同的行。)
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 branch tmp 2cae03e
,您就会将其作为一个分支获取。要将其转换为存储,请运行:
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.
把它作为一个分支还可以让你自由地操作它;例如,挑选它或合并它。
回答by Wade
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”:
$ 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.
当我刚接触 git 时,这对我来说并不清楚,我正在尝试“git show”、“git apply”、“patch”等的不同组合。
回答by Senthil A Kumar
To get the list of stashes that are still in your repository, but not reachable any more:
要获取仍在您的存储库中但无法再访问的存储列表:
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
If you gave a title to your stash, replace "WIP" in -grep=WIP
at the end of the command with a part of your message, e.g. -grep=Tesselation
.
如果您为藏匿处指定了标题,请将-grep=WIP
命令末尾的“WIP”替换为您消息的一部分,例如-grep=Tesselation
.
The command is grepping for "WIP" because the default commit message for a stash is in the form WIP on mybranch: [previous-commit-hash] Message of the previous commit.
该命令正在搜索“WIP”,因为存储的默认提交消息采用以下形式 WIP on mybranch: [previous-commit-hash] Message of the previous commit.
回答by Greg Hewgill
I just constructed a command that helped me find my lost stash 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
This lists all the objects in the .git/objects tree, locates the ones that are of type commit, then shows a summary of each one. From this point it was just a matter of looking through the commits to find an appropriate "WIP on work: 6a9bb2" ("work" is my branch, 619bb2 is a recent commit).
这会列出 .git/objects 树中的所有对象,找到属于 commit 类型的对象,然后显示每个对象的摘要。从这一点来看,只需查看提交即可找到合适的“WIP on work:6a9bb2”(“work”是我的分支,619bb2 是最近的提交)。
I note that if I use "git stash apply" instead of "git stash pop" I wouldn't have this problem, and if I use "git stash save message" then the commit might have been easier to find.
我注意到,如果我使用“git stash apply”而不是“git stash pop”,我就不会有这个问题,如果我使用“git stash save message”,那么提交可能更容易找到。
Update: With Nathan's idea, this becomes shorter:
更新:有了内森的想法,这变得更短:
for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
回答by Nathan Jones
git fsck --unreachable | grep commit
should show the sha1, although the list it returns might be quite large. git show <sha1>
will show if it is the commit you want.
git fsck --unreachable | grep commit
应该显示 sha1,尽管它返回的列表可能很大。git show <sha1>
将显示它是否是您想要的提交。
git cherry-pick -m 1 <sha1>
will merge the commit onto the current branch.
git cherry-pick -m 1 <sha1>
将提交合并到当前分支。
回答by emragins
Windows PowerShell equivalent using gitk:
使用 gitk 的 Windows PowerShell 等效项:
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })
There is probably a more efficient way to do this in one pipe, but this does the job.
在一个管道中可能有一种更有效的方法来做到这一点,但这可以完成工作。
回答by Colin Hebert
If you want to restash a lost stash, you need to find the hash of your lost stash first.
如果您想恢复丢失的存储,您需要先找到丢失的存储的哈希值。
As Aristotle Pagaltzis suggested a git fsck
should help you.
正如亚里士多德 Pagaltzis 建议的那样,git fsck
应该可以帮助您。
Personally I use my log-all
alias which show me every commit (recoverable commits) to have a better view of the situation :
就个人而言,我使用log-all
别名向我展示每次提交(可恢复提交)以更好地了解情况:
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
You can do an even faster search if you're looking only for "WIP on" messages.
如果您只查找“WIP on”消息,则可以进行更快的搜索。
Once you know your sha1, you simply change your stash reflog to add the old stash :
一旦你知道你的 sha1,你只需更改你的 stash reflog 来添加旧的 stash :
git update-ref refs/stash ed6721d
You'll probably prefer to have an associated message so a -m
你可能更喜欢有一个关联的消息,所以 -m
git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d
And you'll even want to use this as an alias :
你甚至想用它作为别名:
restash = !git update-ref -m $(git log -1 --pretty=format:'%s' ) refs/stash
回答by Shaheen Ghiassy
I liked Aristotle's approach, but didn't like using GITK... as I'm used to using GIT from the command line.
我喜欢亚里士多德的方法,但不喜欢使用 GITK……因为我习惯于从命令行使用 GIT。
Instead, I took the dangling commits and output the code to a DIFF file for review in my code editor.
相反,我接受了悬空提交并将代码输出到 DIFF 文件,以便在我的代码编辑器中进行。
git show $( git fsck --no-reflog | awk '/dangling commit/ {print }' ) > ~/stash_recovery.diff
Now you can load up the resulting diff/txt file (its in your home folder) into your txt editor and see the actual code and resulting SHA.
现在您可以将生成的 diff/txt 文件(在您的主文件夹中)加载到您的 txt 编辑器中,并查看实际代码和生成的 SHA。
Then just use
然后只需使用
git stash apply ad38abbf76e26c803b27a6079348192d32f52219
回答by Vivek Kumar
You can list all unreachable commits by writing this command in terminal -
您可以通过在终端中编写此命令来列出所有无法访问的提交 -
git fsck --unreachable
Check unreachable commit hash -
检查无法访问的提交哈希 -
git show hash
Finally apply if you find the stashed item -
如果你找到藏匿的物品,最后申请 -
git stash apply hash