关于恢复:如何恢复Git中丢失的存储?

How to recover a dropped stash in Git?

我经常使用git stashgit stash pop来保存和恢复我的工作树中的更改。昨天我在我的工作树上做了一些改变,我把它们藏起来,然后我对我的工作树做了更多的改变。我想回去回顾一下昨天隐藏的更改,但是git stash pop似乎删除了对相关提交的所有引用。

我知道如果我使用git stash,那么.git/refs/stash包含用于创建stash的提交的引用。和.git/logs/refs/stash包含整个stash。但这些参考文献都是在git stash pop之后。我知道提交仍在我的存储库的某个地方,但我不知道它是什么。

有没有一个简单的方法来恢复昨天的库存承诺参考?

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


一旦你知道你的隐藏的哈希提交下降,你可以把它的应用:

1
git stash apply $stash_hash

或者,你可以创建一个单独的分支,它是以

1
git branch recovered $stash_hash

是的,你可以在任何你想要的,所有正常的工具。当你做,只是吹走的分公司。

寻找在哈希

如果你想跟它的只有终端仍然是开放的,你将仍然有git stash pop哈希值通过屏幕上的印刷(谢谢,逼疯了)。

此外,你可以找到它在Unix或Linux,这是,Git Bash的Windows:

1
git fsck --no-reflog | awk '/dangling commit/ {print $3}'

使用Windows PowerShell的...or:

1
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

这将显示您的所有邮件在您的图,这是尖的时间提交相关的任何分支或标签,每个从每个提交的提交包括隐藏的失落,你所创造的地方,将在这样的图。

easiest找到隐藏的方式提交到你想要到那可能是通gitk列表:

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

从国有企业...or答案emragins如果使用Windows PowerShell。

这将启动你的浏览器显示的每个库的单库所提交的,无论它是否或不可访问的。

你可以有这样的事情gitkgit log --graph --oneline --decorate替换如果你选择好的图上的图形用户界面(GUI)在单独的控制台应用程序。

现场提交到变更的提交信息,看这个表:

# 160 160 # &;&;& # 160 160;和#;在制品在线somebranch:一些老commithash提交留言

注意:只有在这个信息将提交表单("在制品"开始的。)如果你没有当你做git stash供应信息。


如果您没有关闭终端,只需查看git stash pop的输出,就可以得到丢失存储的对象ID。通常看起来是这样的:

1
2
3
$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(注意,git stash drop也产生相同的线。)

要把那东西拿回来,只需运行git branch tmp 2cae03e,你就可以得到它作为一个分支。要将此转换为隐藏,请运行:

1
2
git stash apply tmp
git stash

把它作为一个分支也可以让您自由地操作它;例如,挑选它或合并它。


这就要提到除了在接受的解决方案。它不是立即明显的第一时间我想我这个方法(也许它应该被隐藏,而是利用从哈希值,就用"储藏应用":

1
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

当我是新来的蠢货,这不是我的,我是透明的,尝试不同的组合,使用`git apply"秀"、"补丁",等等。


到这一stashes列表仍然是在您的处置,但不可访问的任何更多。

1
git fsck --unreachable | grep commit | cut -d"" -f3 | xargs git log --merges --no-walk --grep=WIP

如果你把你的标题是隐藏的,在"半成品"-grep=WIPAT命令与结束的部分-grep=Tesselation你的消息,例如。

该命令是"半成品",因为它grepping默认是隐藏的消息是在提交表单WIP on mybranch: [previous-commit-hash] Message of the previous commit.


我只是说我是人工命令:find my隐藏的失落。

1
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 /对象的树,这是一locates型汇总提交的,然后每一个节目。从这一点看,这是个问题,只是通过寻找适当的承诺":一6a9bb2在制品在线工作"("工作"是我的店,是一个新619bb2提交)。

我注意到,如果我使用"储藏"的申请,而不是流行的"储藏",我也不会有这样的问题,"如果我用储藏保存的消息",然后提交,可能已被更容易找到。

更新:这与弥敦道的思想,成为短。

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

git fsck --unreachable | grep commit应该显示它的值列表,但回报可能是相当大的。如果它是git show 将提交显示你想要的。

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


如果你想restash隐藏的失落,你需要找到你丢失的隐藏第一个哈希。

亚里士多德的pagaltzis显示git fsck应该帮助你。

我用我的个人演唱会,我的每一个log-all别名Commit(承诺做一个更好的recoverable)视图的情况:

1
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

你可以更快的搜索,如果你的一只正在寻找"半成品"的消息。

你知道你一次你用你的隐藏的变化值添加到reflog旧藏。

1
git update-ref refs/stash ed6721d

你可能宁愿有一只-m相关消息

1
git update-ref -m"$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

和你甚至想用这一别名:

1
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文件中,以便在代码编辑器中查看。

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

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

然后就用

1
git stash apply ad38abbf76e26c803b27a6079348192d32f52219

在使用Git2.6.4的OSX中,我只是不小心运行了GitStash 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

然后当你找到提交ID时,点击git stash apply提交ID

希望这能尽快帮助别人


为什么人们会问这个问题?因为他们还不知道或者不了解反射波。

这个问题的大多数答案给出了长命令和选项,几乎没有人会记得。所以,人们开始思考这个问题,复制粘贴他们认为他们需要的东西,然后马上就忘记了。

我建议每个有这个问题的人只检查reflog(git reflog),不要超过这个。一旦您看到了所有提交的列表,就有100种方法可以找到您要寻找的提交,并从中挑选它或创建一个分支。在这个过程中,您将了解到reflog以及各种基本git命令的有用选项。


我想向接受的解决方案中添加另一种很好的方法来完成所有的更改,当您没有可用的Gitk或没有用于输出的x时。

1
2
3
git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

然后,您会得到一个接一个显示的哈希的所有差异。按"Q"进入下一个差异。


亚里士多德接受的答案将显示所有可达到的承诺,包括非藏状的承诺。过滤噪音:

1
2
3
4
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开启"。

请记住,如果您用一条消息(如git stash save"My newly created stash"保存了您的库存,这将覆盖默认的"WIP开启…"消息。

您可以显示关于每个提交的更多信息,例如显示提交消息,或将其传递给git stash show

1
2
3
4
5
6
7
8
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

在一个简单的命令窗口(在我的例子中是Windows7)中,我无法得到任何在Windows上工作的答案。awkgrepSelect-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)

也许不是最好的解决办法,但对我很有效


通过在终端中写入此命令,可以列出所有无法到达的提交。-

1
git fsck --unreachable

检查不可访问的提交哈希-

1
git show hash

找到藏品后再申请-

1
git stash apply hash

通过以下步骤恢复:

  • 标识已删除的存储哈希代码:

    Gitk--全部$(Git fsck--无reflog awk'/dangling commit/打印$3')

  • 樱桃挑选藏品:

    Git Cherry Pick-M 1$stash_hash_代码

  • 解决冲突,如果使用:

    吉特混血儿

  • 另外,如果使用gerrit,那么提交消息可能会有问题。请在以下备选方案之前保存您的更改:

  • 使用硬重置到上一次提交,然后重新提交此更改。
  • 您还可以保存更改,重新设置和重新提交。

  • 我来这里是想知道如何把藏品拿回来,不管我签了什么。特别是,我藏了一些东西,然后检查了一个旧版本,然后弹出了它,但在那个早期的时间点,藏的是一个不可操作的,所以藏的消失了;我不能只是做git stash把它推回到堆栈上。这对我很有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ 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.

    回想起来,我应该使用git stash apply,而不是git stash pop。我在做一个bisect,有一个小补丁,我想在每个bisect步骤上应用。现在我要做的是:

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


    我无意中把Gitup应用程序中的藏匿物移除了。只需按ctrl+z撤消。

    也许这对某人有帮助;)