如何在Git中恢复被删除的存储?

时间:2021-06-01 00:01:44

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 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.

我知道如果我使用git stash,那么.git / refs / stash包含用于创建存储的提交的引用。而.git / logs / refs / stash包含整个存储。但这些引用在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!

请注意,这对我来说并不重要,因为我每天都有备份,可以回到昨天的工作树来获取我的更改。我问,因为必须有一个更简单的方法!

19 个解决方案

#1


2247  

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

...or using Powershell for Windows:

...或者使用Powershell for Windows:

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 $3}' )

...or see the answer from emragins if using Powershell for Windows.

...或者如果使用Powershell for Windows,请查看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.

你可以用git log --graph --oneline --decorate替换gitk,如果你喜欢在一个单独的GUI应用程序上的控制台上有一个漂亮的图形。

To spot stash commits, look for commit messages of this form:

要查找存储提交,请查找此表单的提交消息:

        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.

注意:如果您在执行git stash时未提供消息,则提交消息将仅采用此形式(以“WIP on”开头)。

Once you know the hash of the commit you want, you can apply it as a stash:

一旦知道了所需提交的哈希值,就可以将其应用为存储:

git stash apply $stash_hash

Or you can use the context menu in gitk to create branches for any unreachable commits you are interested in. After that, you can do whatever you want with them with all the normal tools. When you’re done, just blow those branches away again.

或者您可以使用gitk中的上下文菜单为您感兴趣的任何无法访问的提交创建分支。之后,您可以使用所有常规工具随意执行任何操作。当你完成后,再次吹走那些树枝。

#2


634  

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.

将它作为分支也允许您*地操作它;例如,樱桃挑选或合并它。

#3


242  

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”等的不同组合。

#4


70  

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

#5


70  

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”进行grepping,因为存储的默认提交消息的格式为WIP on mybranch:[previous-commit-hash]上一次提交的消息。

#6


37  

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 将显示它是否是您想要的提交。

git cherry-pick -m 1 <sha1> will merge the commit onto the current branch.

git cherry-pick -m 1 会将提交合并到当前分支上。

#7


24  

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.

正如Aristotle 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,你只需更改你的存储reflog以添加旧的存储:

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' $1) refs/stash $1

#8


15  

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 $3}' ) > ~/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

#9


14  

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“(悬空提交)(。*)”|%{$ _。Line.Split('')[2]})

There is probably a more efficient way to do this in one pipe, but this does the job.

可能有一种更有效的方法在一个管道中执行此操作,但这可以完成这项工作。

#10


12  

In OSX with git v2.6.4, I just run git stash drop accidentally, then I found it by going trough below steps

在使用git v2.6.4的OSX中,我只是意外地运行git stash drop,然后我通过下面的步骤找到了它

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>

$ git fsck --unreachable | grep commit |切-c 20- | xargs git show | grep -B 6 -A 2 <藏匿名称>

otherwise you will find ID from the result by manually with:

否则你将通过手动找到结果中的ID:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

$ git fsck --unreachable | grep commit |切-c 20- | xargs git show

Then when you find the commit-id just hit the git stash apply {commit-id}

然后,当你发现commit-id刚刚点击git stash时,应用{commit-id}

Hope this helps someone quickly

希望这可以帮助别人

#11


11  

Why do people ask this question? Because they don't yet know about or understand the reflog.

为什么人们会问这个问题?因为他们还不了解或了解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.

我会建议大家用这个问题来检查reflog(git reflog),不仅如此。一旦你看到所有提交的列表,有一百种方法可以找出你正在寻找的提交,并挑选它或从中创建一个分支。在这个过程中,您将了解各种基本git命令的reflog和有用选项。

#12


10  

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.

我想添加到已接受的解决方案另一个好方法来完成所有更改,当你没有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

Then you get all the diffs for those hashes displayed one after another. Press 'q' to get to the next diff.

然后你会得到一个接一个显示的哈希的所有差异。按'q'进入下一个差异。

#13


9  

The accepted answer by Aristotle will show all reachable commits, including non-stash-like commits. To filter out the noise:

亚里士多德接受的答案将显示所有可到达的提交,包括非存储类提交。滤除噪音:

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

This will only include commits which have exactly 3 parent commits (which a stash will have), and whose message includes "WIP on".

这将只包括具有3个父提交(存储将具有)的提交,并且其消息包括“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.

请记住,如果您使用消息保存了存储(例如git stash save“我新创建的存储”),这将覆盖默认的“WIP on ...”消息。

You can display more information about each commit, e.g. display the commit message, or pass it to git stash show:

您可以显示有关每个提交的更多信息,例如显示提交消息,或将其传递给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

#14


8  

I couldn't get any of the answers to work on Windows in a simple command window (Windows 7 in my case). awk, grep and Select-string weren't recognized as commands. So I tried a different approach:

我无法在一个简单的命令窗口(在我的例子中是Windows 7)中获得在Windows上工作的任何答案。 awk,grep和Select-string未被识别为命令。所以我尝试了一种不同的方法:

  • first run: git fsck --unreachable | findstr "commit"
  • 首先运行:git fsck --unreachable | findstr“commit”

  • copy the output to notepad
  • 将输出复制到记事本

  • find replace "unreachable commit" with start cmd /k git show
  • 使用start cmd / k git show替换“unreachable commit”

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

启动CMD / K GIT中显示8506d235f935b92df65d58e7d75e9441220537a4启动CMD / K GIT中显示44078733e1b36962571019126243782421fcd8ae启动CMD / K GIT中显示ec09069ec893db4ec1901f94eefc8dc606b1dbf1启动CMD / K GIT中显示d00aab9198e8b81d052d90720165e48b287c302e

  • save as a .bat file and run it
  • 另存为.bat文件并运行它

  • the script will open a bunch of command windows, showing each commit
  • 该脚本将打开一堆命令窗口,显示每个提交

  • if you found the one you're looking for, run: git stash apply (your hash)
  • 如果你找到了你正在寻找的那个,运行:git stash apply(你的哈希)

may not be the best solution, but worked for me

可能不是最好的解决方案,但对我有用

#15


7  

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

#16


4  

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:

我来这里寻找的是如何实际获得藏匿,无论我检查了什么。特别是,我藏了些东西,然后检查了一个旧的版本,然后加油,但是那个藏匿处在那个早期的时间点是无操作的,所以藏匿物消失了;我不能只是把git stash推回堆栈。这对我有用:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

In retrospect, I should have been using git stash apply not git stash pop. I was doing a bisect and had a little patch that I wanted to apply at every bisect step. Now I'm doing this:

回想起来,我应该一直使用git stash apply而不是git stash pop。我正在做一个bisect并且有一个小补丁我想在每个bisect步骤中应用。现在我这样做:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

#17


4  

Recovered it by using following steps:

通过使用以下步骤恢复它:

  1. Identify the deleted stash hash code:

    识别已删除的存储哈希码:

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

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

  2. Cherry Pick the Stash:

    Cherry Pick the Stash:

    git cherry-pick -m 1 $stash_hash_code

    git cherry-pick -m 1 $ stash_hash_code

  3. 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:

另外,如果您使用的是gerrit,则可能会遇到提交消息的问题。请在遵循下一个备选方案之前隐藏您的更改:

  1. Use hard reset to previous commit and then recommit this change.
  2. 使用硬重置到先前的提交,然后重新发送此更改。

  3. You may also stash the change, rebase and recommit.
  4. 您也可以隐藏变更,重新定义和重新发送。

#18


0  

Another common use case: You tried popping onto the wrong branch and got conflicts?

另一个常见的用例:你试过弹出错误的分支并发生冲突?

All you want is to undo the pop but still keep it in the stash list so you can pop it out on the correct branch.

你想要的只是撤消pop,但仍然将它保存在存储列表中,这样你就可以在正确的分支上弹出它。

To fix it, do the following:

要解决此问题,请执行以下操作:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Done!

#19


0  

I did accidently removed the stash in GitUP app. Just press Ctrl+Z to undone it.

我确实意外地删除了GitUP应用程序中的藏匿处。只需按Ctrl + Z即可撤消它。

Maybe it helps somebody ;)

也许它有助于某人;)

#1


2247  

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

...or using Powershell for Windows:

...或者使用Powershell for Windows:

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 $3}' )

...or see the answer from emragins if using Powershell for Windows.

...或者如果使用Powershell for Windows,请查看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.

你可以用git log --graph --oneline --decorate替换gitk,如果你喜欢在一个单独的GUI应用程序上的控制台上有一个漂亮的图形。

To spot stash commits, look for commit messages of this form:

要查找存储提交,请查找此表单的提交消息:

        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.

注意:如果您在执行git stash时未提供消息,则提交消息将仅采用此形式(以“WIP on”开头)。

Once you know the hash of the commit you want, you can apply it as a stash:

一旦知道了所需提交的哈希值,就可以将其应用为存储:

git stash apply $stash_hash

Or you can use the context menu in gitk to create branches for any unreachable commits you are interested in. After that, you can do whatever you want with them with all the normal tools. When you’re done, just blow those branches away again.

或者您可以使用gitk中的上下文菜单为您感兴趣的任何无法访问的提交创建分支。之后,您可以使用所有常规工具随意执行任何操作。当你完成后,再次吹走那些树枝。

#2


634  

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.

将它作为分支也允许您*地操作它;例如,樱桃挑选或合并它。

#3


242  

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”等的不同组合。

#4


70  

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

#5


70  

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”进行grepping,因为存储的默认提交消息的格式为WIP on mybranch:[previous-commit-hash]上一次提交的消息。

#6


37  

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 将显示它是否是您想要的提交。

git cherry-pick -m 1 <sha1> will merge the commit onto the current branch.

git cherry-pick -m 1 会将提交合并到当前分支上。

#7


24  

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.

正如Aristotle 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,你只需更改你的存储reflog以添加旧的存储:

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' $1) refs/stash $1

#8


15  

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 $3}' ) > ~/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

#9


14  

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“(悬空提交)(。*)”|%{$ _。Line.Split('')[2]})

There is probably a more efficient way to do this in one pipe, but this does the job.

可能有一种更有效的方法在一个管道中执行此操作,但这可以完成这项工作。

#10


12  

In OSX with git v2.6.4, I just run git stash drop accidentally, then I found it by going trough below steps

在使用git v2.6.4的OSX中,我只是意外地运行git stash drop,然后我通过下面的步骤找到了它

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>

$ git fsck --unreachable | grep commit |切-c 20- | xargs git show | grep -B 6 -A 2 <藏匿名称>

otherwise you will find ID from the result by manually with:

否则你将通过手动找到结果中的ID:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

$ git fsck --unreachable | grep commit |切-c 20- | xargs git show

Then when you find the commit-id just hit the git stash apply {commit-id}

然后,当你发现commit-id刚刚点击git stash时,应用{commit-id}

Hope this helps someone quickly

希望这可以帮助别人

#11


11  

Why do people ask this question? Because they don't yet know about or understand the reflog.

为什么人们会问这个问题?因为他们还不了解或了解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.

我会建议大家用这个问题来检查reflog(git reflog),不仅如此。一旦你看到所有提交的列表,有一百种方法可以找出你正在寻找的提交,并挑选它或从中创建一个分支。在这个过程中,您将了解各种基本git命令的reflog和有用选项。

#12


10  

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.

我想添加到已接受的解决方案另一个好方法来完成所有更改,当你没有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

Then you get all the diffs for those hashes displayed one after another. Press 'q' to get to the next diff.

然后你会得到一个接一个显示的哈希的所有差异。按'q'进入下一个差异。

#13


9  

The accepted answer by Aristotle will show all reachable commits, including non-stash-like commits. To filter out the noise:

亚里士多德接受的答案将显示所有可到达的提交,包括非存储类提交。滤除噪音:

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

This will only include commits which have exactly 3 parent commits (which a stash will have), and whose message includes "WIP on".

这将只包括具有3个父提交(存储将具有)的提交,并且其消息包括“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.

请记住,如果您使用消息保存了存储(例如git stash save“我新创建的存储”),这将覆盖默认的“WIP on ...”消息。

You can display more information about each commit, e.g. display the commit message, or pass it to git stash show:

您可以显示有关每个提交的更多信息,例如显示提交消息,或将其传递给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

#14


8  

I couldn't get any of the answers to work on Windows in a simple command window (Windows 7 in my case). awk, grep and Select-string weren't recognized as commands. So I tried a different approach:

我无法在一个简单的命令窗口(在我的例子中是Windows 7)中获得在Windows上工作的任何答案。 awk,grep和Select-string未被识别为命令。所以我尝试了一种不同的方法:

  • first run: git fsck --unreachable | findstr "commit"
  • 首先运行:git fsck --unreachable | findstr“commit”

  • copy the output to notepad
  • 将输出复制到记事本

  • find replace "unreachable commit" with start cmd /k git show
  • 使用start cmd / k git show替换“unreachable commit”

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

启动CMD / K GIT中显示8506d235f935b92df65d58e7d75e9441220537a4启动CMD / K GIT中显示44078733e1b36962571019126243782421fcd8ae启动CMD / K GIT中显示ec09069ec893db4ec1901f94eefc8dc606b1dbf1启动CMD / K GIT中显示d00aab9198e8b81d052d90720165e48b287c302e

  • save as a .bat file and run it
  • 另存为.bat文件并运行它

  • the script will open a bunch of command windows, showing each commit
  • 该脚本将打开一堆命令窗口,显示每个提交

  • if you found the one you're looking for, run: git stash apply (your hash)
  • 如果你找到了你正在寻找的那个,运行:git stash apply(你的哈希)

may not be the best solution, but worked for me

可能不是最好的解决方案,但对我有用

#15


7  

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

#16


4  

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:

我来这里寻找的是如何实际获得藏匿,无论我检查了什么。特别是,我藏了些东西,然后检查了一个旧的版本,然后加油,但是那个藏匿处在那个早期的时间点是无操作的,所以藏匿物消失了;我不能只是把git stash推回堆栈。这对我有用:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

In retrospect, I should have been using git stash apply not git stash pop. I was doing a bisect and had a little patch that I wanted to apply at every bisect step. Now I'm doing this:

回想起来,我应该一直使用git stash apply而不是git stash pop。我正在做一个bisect并且有一个小补丁我想在每个bisect步骤中应用。现在我这样做:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

#17


4  

Recovered it by using following steps:

通过使用以下步骤恢复它:

  1. Identify the deleted stash hash code:

    识别已删除的存储哈希码:

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

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

  2. Cherry Pick the Stash:

    Cherry Pick the Stash:

    git cherry-pick -m 1 $stash_hash_code

    git cherry-pick -m 1 $ stash_hash_code

  3. 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:

另外,如果您使用的是gerrit,则可能会遇到提交消息的问题。请在遵循下一个备选方案之前隐藏您的更改:

  1. Use hard reset to previous commit and then recommit this change.
  2. 使用硬重置到先前的提交,然后重新发送此更改。

  3. You may also stash the change, rebase and recommit.
  4. 您也可以隐藏变更,重新定义和重新发送。

#18


0  

Another common use case: You tried popping onto the wrong branch and got conflicts?

另一个常见的用例:你试过弹出错误的分支并发生冲突?

All you want is to undo the pop but still keep it in the stash list so you can pop it out on the correct branch.

你想要的只是撤消pop,但仍然将它保存在存储列表中,这样你就可以在正确的分支上弹出它。

To fix it, do the following:

要解决此问题,请执行以下操作:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Done!

#19


0  

I did accidently removed the stash in GitUP app. Just press Ctrl+Z to undone it.

我确实意外地删除了GitUP应用程序中的藏匿处。只需按Ctrl + Z即可撤消它。

Maybe it helps somebody ;)

也许它有助于某人;)