如何恢复 Git 中丢失的存储?
我经常使用 git stash 和 git stash pop 来保存和恢复工作树中的更改。 昨天,我对工作树进行了一些更改,将其隐藏并弹出,然后对工作树进行了更多更改。 我想返回并查看昨天隐藏的更改,但 git stash pop 似乎删除了对相关提交的所有引用。
我知道如果我使用 git stash 则 .git/refs/stash 包含用于创建存储的提交的引用。 .git/logs/refs/stash 包含整个存储。 但这些引用在 git stash pop 后就消失了。 我知道该提交仍在我的存储库中的某个位置,但我不知道它是什么。
有没有一种简单的方法来恢复昨天的存储提交引用?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
知道大致的文件名及其位置,并且能够通过 greping 悬挂提交查找路径来找到已删除的存储文件
Knowing the approximate file name and it's location, and was able to find dropped stash files grepping dangling commits for path
不完全是获得存储的答案,但如果目标是获得未提交的更改,这些更改首先存储然后弹出到另一个分支中,但对于两者都意味着并按以下方式完成:
branch_a
中进行更改branch_a
创建branch_bgit stash apply
然后恢复对
branch_a
未提交的更改:git checkout分支_a
Not exactly an answer to get a stash but if the goal is to get uncommited changes that were first stashed and then popped in another branch but meant for both and done in the following way:
branch_a
git stash
branch_a
git stash apply
Then to restore the uncommited changes to
branch_a
:git checkout branch_a
git merge branch_b
git reset HEAD~1
您可以逐步遵循以下过程:
1- 使用下面列出所有无法访问的提交
git fsck --unreachable
2- 显示无法访问的提交哈希
git show hash
3-复制所有日志,您可以看到类似日志,无法访问的blob,提交,树。
4-应用 git stash 和具有提交哈希的日志
git stash apply [替换哈希]
You can follow the below process step by step:
1- use below to list all unreachable commits
git fsck --unreachable
2- to show unreachable commit hash by
git show hash
3- copy all log, you can see log like, unreachable blob, commit, tree.
4- apply git stash with log having commit hash
git stash apply [replace hash]
这对我(2022 年)有用,可以从 Windows 环境恢复 git 中意外删除的存储。
这些步骤概述了如何恢复任何已删除的 git 存储或分支(假设它尚未被垃圾收集永久删除)。
导航到您的项目所在的目录。
输入命令:
git fsck --no-reflogs | 找到“悬空提交”
将会出现悬空提交的哈希值列表。 这些将包含已删除的分支和存储。 首先复制并粘贴列表末尾附近的哈希值以查找您的存储或分支。 例如,使用命令:
git log -1 [hash]
如果相应的哈希与您尝试恢复的内容匹配,请使用以下命令来恢复它”
git stash apply [哈希]
This worked for me (in 2022) with recovering my accidently deleted stash in git from a windows environment.
These steps outline how to recover any deleted git stashes or branches (assuming it has not been permanently delete by garbage collection).
Navigate to the directory where your project located.
Enter the command:
git fsck --no-reflogs | find "dangling commit"
A list of hashes for dangling commits will appear. These will consist of branches and stashes that were deleted. Start with copy and pasting the hashes near the end of the list to find your stash or branch. For example, use the command:
git log -1 [hash]
If the corresponding hash matches what you are trying to recover, use the following command to restore it"
git stash apply [hash]
使用 gitk 的 Windows PowerShell 等效项:
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[ 2] })
可能有一种更有效的方法可以在一个管道中执行此操作,但这可以完成工作。
Windows PowerShell equivalent using gitk:
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.
我刚刚构建了一个命令来帮助我找到丢失的存储提交:
这会列出 .git/objects 树中的所有对象,找到提交类型的对象,然后显示每个对象的摘要。 从这一点来看,只需查看提交以找到合适的“工作中的 WIP:6a9bb2”(“工作”是我的分支,619bb2 是最近的提交)。
我注意到,如果我使用“git stash apply”而不是“git stash pop”,我就不会出现这个问题,如果我使用“git stash save message”,那么提交可能会更容易去寻找。
更新:根据内森的想法,这变得更短:
I just constructed a command that helped me find my lost stash commit:
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).
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.
Update: With Nathan's idea, this becomes shorter:
git fsck --无法访问 | grep commit 应该显示 sha1,尽管它返回的列表可能相当大。
git show
将显示这是否是您想要的提交。gitcherry-pick -m 1
会将提交合并到当前分支。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 cherry-pick -m 1 <sha1>
will merge the commit onto the current branch.如果您想重新存储丢失的存储,您需要首先找到丢失的存储的哈希值。
正如 Aristotle Pagaltzis 建议的那样,
git fsck
应该可以帮助您。就我个人而言,我使用我的
log-all
别名来显示每个提交(可恢复的提交),以便更好地了解情况:如果您只查找“WIP on ”消息。
一旦您知道了您的 sha1,您只需更改您的存储引用日志即可添加旧的存储:
您可能更喜欢有一个关联的消息,因此
-m
您甚至会想将其用作别名:
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.Personally I use my
log-all
alias which show me every commit (recoverable commits) to have a better view of the situation :You can do an even faster search if you're looking only for "WIP on" messages.
Once you know your sha1, you simply change your stash reflog to add the old stash :
You'll probably prefer to have an associated message so a
-m
And you'll even want to use this as an alias :
我最喜欢的是这句话:
这基本上与这个答案相同,但要短得多。 当然,你仍然可以添加
--graph
来获得树状显示。当您在列表中找到提交后,请使用
对于我来说,使用
--no-reflogs
确实显示了丢失的存储条目,但是--unreachable
(如在许多其他答案)没有。当你在 Windows 下时,在 git bash 上运行它。
鸣谢:上述命令的详细信息取自 https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf< /a>
My favorite is this one-liner:
This is basically the same idea as this answer but much shorter. Of course, you can still add
--graph
to get a tree-like display.When you have found the commit in the list, apply with
For me, using
--no-reflogs
did reveal the lost stash entry, but--unreachable
(as found in many other answers) did not.Run it on git bash when you are under Windows.
Credits: The details of the above commands are taken from https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf
您可以通过在终端中编写此命令来列出所有无法访问的提交 -
检查无法访问的提交哈希 -
如果找到隐藏的项目,最后应用 -
You can list all unreachable commits by writing this command in terminal -
Check unreachable commit hash -
Finally apply if you find the stashed item -
我喜欢亚里士多德的方法,但不喜欢使用 GITK...因为我习惯从命令行使用 GIT。
相反,我采用了悬空提交并将代码输出到 DIFF 文件,以便在代码编辑器中进行审查。
现在,您可以将生成的 diff/txt 文件(位于您的主文件夹中)加载到 txt 编辑器中,并查看实际代码和生成的 SHA。
然后只需使用
I liked Aristotle's approach, but didn't like using GITK... as I'm used to using GIT from the command line.
Instead, I took the dangling commits and output the code to a DIFF file for review in my code editor.
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.
Then just use
在使用 git v2.6.4 的 OSX 中,我只是意外地运行 git stash drop ,然后我通过以下步骤找到了它
如果您知道存储的名称,则使用:
$ git fsck --unreachable | grep 提交 | 切-c 20- | xargs git 显示 | grep -B 6 -A 2 <存储的名称>
否则,您将通过手动方式从结果中找到 ID:
$ git fsck --unreachable | grep 提交 | 切-c 20- | xargs git show
然后,当你找到 commit-id 时,只需点击 git stash apply {commit-id}
希望这可以快速帮助别人
In OSX with git v2.6.4, I just run git stash drop accidentally, then I found it by going trough below steps
If you know name of the stash then use:
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>
otherwise you will find ID from the result by manually with:
$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show
Then when you find the commit-id just hit the git stash apply {commit-id}
Hope this helps someone quickly
为什么人们会问这个问题? 因为他们还不知道或理解转发日志。
这个问题的大多数答案都给出了很长的命令和几乎没有人会记住的选项。 因此,人们遇到这个问题时,会复制粘贴他们认为需要的任何内容,然后几乎立即忘记它。
我建议有这个问题的每个人只检查引用日志(git reflog),仅此而已。 一旦您看到所有提交的列表,就有一百种方法可以找到您正在寻找的提交并挑选它或从中创建分支。 在此过程中,您将了解 reflog 以及各种基本 git 命令的有用选项。
Why do people ask this question? Because they don't yet know about or understand the reflog.
Most answers to this question give long commands with options almost nobody will remember. So people come into this question and copy paste whatever they think they need and forget it almost immediately after.
I would advise everyone with this question to just check the reflog (git reflog), not much more than that. Once you see that list of all commits there are a hundred ways to find out what commit you're looking for and to cherry-pick it or create a branch from it. In the process you'll have learned about the reflog and useful options to various basic git commands.
我无法在简单的命令窗口(在我的例子中是 Windows 7)中获得在 Windows 上工作的任何答案。
awk
、grep
和Select-string
未被识别为命令。 所以我尝试了一种不同的方法:start cmd /k git show
替换“unreachable commit”将如下所示:
start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4
启动 cmd /k git show 44078733e1b36962571019126243782421fcd8ae
启动 cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1
start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e
git stash apply (your hash)
可能不是最好的解决方案,但对我有用
I couldn't get any of the answers to work on Windows in a simple command window (Windows 7 in my case).
awk
,grep
andSelect-string
weren't recognized as commands. So I tried a different approach:git fsck --unreachable | findstr "commit"
start cmd /k git show
will look something like this:
start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4
start cmd /k git show 44078733e1b36962571019126243782421fcd8ae
start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1
start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e
git stash apply (your hash)
may not be the best solution, but worked for me
当您没有可用的 gitk 或没有 X 用于输出时,我想向已接受的解决方案添加另一种完成所有更改的好方法。
然后你会得到一个又一个显示的这些哈希值的所有差异。 按“q”进入下一个差异。
I want to add to the accepted solution another good way to go through all the changes, when you either don't have gitk available or no X for output.
Then you get all the diffs for those hashes displayed one after another. Press 'q' to get to the next diff.
亚里士多德接受的答案将显示所有可到达的提交,包括非存储类提交。 过滤掉噪音:
这将只包括恰好有 3 个父提交(存储将有)的提交,并且其消息包含“WIP on”。
请记住,如果您使用消息保存存储(例如
git stash save“我新创建的存储”
),这将覆盖默认的“WIP on...”消息。您可以显示有关每个提交的更多信息,例如显示提交消息,或将其传递给 git stash show :
The accepted answer by Aristotle will show all reachable commits, including non-stash-like commits. To filter out the noise:
This will only include commits which have exactly 3 parent commits (which a stash will have), and whose message includes "WIP on".
Keep in mind, that if you saved your stash with a message (e.g.
git stash save "My newly created stash"
), this will override the default "WIP on..." message.You can display more information about each commit, e.g. display the commit message, or pass it to
git stash show
:要获取仍在存储库中但无法再访问的存储列表:
如果您为存储提供了标题,请在命令末尾替换
-grep=WIP
中的“WIP”包含消息的一部分,例如-grep=Tesselation
。该命令正在 grep 查找“WIP”,因为存储的默认提交消息的格式为
WIP on mybranch: [previous-commit-hash] 上一次提交的消息。
当您找到提交时,使用 git stash apply应用它
To get the list of stashes that are still in your repository, but not reachable any more:
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
.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.
When you have found the commit, apply it with
git stash apply <commit_hash>
只是想提及已接受的解决方案中的这一补充。 当我第一次尝试这个方法时,这对我来说并不是很明显(也许应该是),但是要应用哈希值中的存储,只需使用“git stash apply”:
当我刚接触 git 时,这不是我不清楚,我正在尝试“git show”、“git apply”、“patch”等的不同组合。
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 ":
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 stash 来将其推回到堆栈上。 这对我有用:
回想起来,我应该使用 git stash apply ,而不是 git stash pop 。 我正在做一个
bisect
并且有一个小补丁,我想在每个bisect
步骤中应用它。 现在我正在这样做:What I came here looking for is how to actually get the stash back, regardless of what I have checked out. In particular, I had stashed something, then checked out an older version, then poped it, but the stash was a no-op at that earlier time point, so the stash disappeared; I couldn't just do
git stash
to push it back on the stack. This worked for me:In retrospect, I should have been using
git stash apply
notgit stash pop
. I was doing abisect
and had a little patch that I wanted to apply at everybisect
step. Now I'm doing this:要在终端中查看提交,只过滤我们关心的提交:
这是基于 Aristotle Pagaltzis 的答案。
To see the commits in terminal, only filtering the ones we care about we can use:
This is based on Aristotle Pagaltzis answer.
要仅查看存储提交、它们附加的位置以及其内容是什么
结果示例
命令
%h
更改为%H
恢复样本
To see only stash commits, where they attached, and what their contents are
result sample
command
%h
to%H
git fsck --dangling | tail -100 | awk ...
recover sample
使用以下步骤恢复它:
识别已删除的存储哈希代码:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
Cherry Pick the Stash:
gitcherry-pick -m 1 $stash_hash_code
解决冲突(如果有)使用:
git mergetool
此外,如果您使用 gerrit,则可能会遇到提交消息问题。 请在执行下一个替代方案之前存储您的更改:
Recovered it by using following steps:
Identify the deleted stash hash code:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
Cherry Pick the Stash:
git cherry-pick -m 1 $stash_hash_code
Resolve Conflicts if any using:
git mergetool
Additionally you might be having issues with commit message if you are using gerrit. Please Stash your changes before following next alternatives:
Github Desktop
如果您使用 Github Desktop 存储了更改,并且意外删除了存储的更改,那么您可以运行以下命令来搜索悬空存储提交(基于 这个答案):
注意:如果使用 Windows,请使用 Git Bash(与 git 安装一起安装)运行命令,
您将获得一个提交列表,例如:
获取提交列表中第一个的。 在上面的示例中,它将是
b7f1b023
并运行以下命令:这将恢复您的更改。 如果没有,您可以尝试输出中的其他提交。
Github Desktop
If you stashed your changes using Github Desktop, and accidentally removed your stashed changes, then you can run the following to search for dangling stash commit (based on this answer):
Note: If using Windows, run the commands using Git Bash (which is installed alongside git installation)
You will get a list of commits like:
Get the commit of the first one in the list. In the above example, it will be
b7f1b023
and run the following:This will recover your changes. If it doesn't, you can try other commits in the output.
一旦你知道了你删除的存储提交的哈希值,你就可以将它作为存储应用:
或者,你可以为它创建一个单独的分支,
之后,你可以使用所有普通工具做任何你想做的事情。 完成后,只需将树枝吹走即可。
查找哈希
如果您刚刚弹出它并且终端仍然打开,您将 屏幕上仍然有
git stash pop
打印的哈希值(谢谢,Dolda)。否则,您可以在 Linux、Unix 或 Windows 上使用 Git Bash 来找到它:
...或在 Windows 上使用 PowerShell:
这将在提交图的提示处显示所有不再从任何分支引用的提交,或者标签 – 每个丢失的提交,包括您创建的每个存储提交,都将位于该图表中的某个位置。
找到所需的存储提交的最简单方法可能是将该列表传递给 gitk:
...或参见 emragins 的答案(如果使用 Windows 版 PowerShell)。
这将启动一个存储库浏览器,向您显示存储库中的每一次提交,无论它是否可访问。
如果您更喜欢控制台上的漂亮图表而不是单独的 GUI 应用程序,则可以将其中的 gitk 替换为 git log --graph --oneline --decorate 之类的内容。
要发现存储提交,请查找以下形式的提交消息
: 某个分支上的 WIP:commithash 一些旧的提交消息
注意:提交消息仅采用这种形式(以“WIP on”开头),如果当您执行
git stash
时,您没有提供消息。Once you know the hash of the stash commit you dropped, you can apply it as a stash:
Or, you can create a separate branch for it with
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).Otherwise, you can find it using this for Linux, Unix or Git Bash for Windows:
...or using PowerShell for Windows:
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
:...or see the answer from emragins if using PowerShell for Windows.
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 likegit 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
.如果您没有关闭终端,只需查看 git stash pop 的输出,您就会获得删除的存储的对象 ID。 它通常看起来像这样:(
请注意,
git stash drop
也会生成相同的行。)要取回该存储,只需运行
git Branch tmp 2cae03e
,然后您就会将其作为分支。 要将其转换为存储,请运行:将其作为分支还可以让您自由地操作它; 例如,挑选它或合并它。
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:(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:Having it as a branch also allows you to manipulate it freely; for example, to cherry-pick it or merge it.