reset撤销 - git本地回滚




如何恢复Git中丢失的存储? (12)

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

我知道如果我使用git stash那么.git / refs / stash包含用于创建存储的提交的引用。 .git / logs / refs / stash包含整个藏匿处。 但是这些引用在git stash pop之后就消失了。 我知道提交仍然存在于我的仓库中,但我不知道它是什么。

有没有简单的方法来恢复昨天的隐藏提交参考?

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


Aristotle接受的答案将显示所有可访问的提交,包括非隐藏式提交。 过滤掉噪音:

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

git fsck --unreachable | grep commit git fsck --unreachable | grep commit应该显示sha1,尽管它返回的列表可能非常大。 git show <sha1>会显示它是否是你想要的提交。

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


使用gitk的Windows PowerShell等价物:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

在一个管道中可能有更高效的方法来做到这一点,但这是做这项工作的。


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

所有你想要的是撤消流行音乐,但仍然保存在存储列表中,以便您可以将其弹出到正确的分支上。

要修复它,请执行以下操作:

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

完成!


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

如果你知道藏匿的名字,然后使用:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

否则您将通过以下方式手动从结果中找到ID:

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

然后,当你找到commit-id时,只需按下git stash apply {commit-id}

希望这可以帮助快速的人


如果你只弹出它并且终端仍然打开,你仍然可以在屏幕上用git stash pop打印散列值 (谢谢Dolda)。

否则,你可以在Linux和Unix上使用它找到它:

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

和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}' )

这将启动一个存储库浏览器,向您显示存储库中的每一次提交 ,无论它是否可访问。

如果你喜欢在单独的GUI应用程序上的控制台上的一个很好的图形,你可以用git log --graph --oneline --decorate来代替那里的gitk

要发现隐藏提交,请查找此窗体的提交消息:

WIP on somebranchcommithash一些旧的提交消息

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

一旦你知道你想要的提交的散列,你可以将它作为一个存储:

git stash apply $stash_hash

或者你可以使用gitk的上下文菜单来创建你感兴趣的任何无法访问的提交的分支。之后,你可以用所有普通工具对它们进行任何你想做的事情。 当你完成后,再把这些树枝吹走。


如果您想恢复丢失的藏匿物,您需要首先找到遗失藏匿物的散列。

正如Aristotle 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,你只需要改变你的存储引用来添加旧的存储:

git update-ref refs/stash ed6721d

你可能更喜欢有一个关联的消息,所以-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

您可以通过在终端中编写此命令列出所有不可访问的提交 -

git fsck --unreachable

检查无法访问的提交哈希 -

git show hash

最后申请,如果你找到隐藏物品 -

git stash apply hash

我到这里寻找的是如何真正获得隐藏,无论我已经检查了什么。 特别是,我藏了一些东西,然后检查出一个旧版本,然后把它放了下来,但是在那个较早的时间点,这个存储器是没有操作的,所以存储器消失了。 我不能只是把git stash把它推回栈上。 这对我有效:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/[email protected]{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并且有一个小补丁,我想在每个平分步骤中应用。 现在我正在这样做:

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

我喜欢Aristotle的方法,但不喜欢使用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

我无法在简单的命令窗口中获得任何在Windows上工作的答案(在我的情况下是Windows 7)。 awkgrepSelect-string不被识别为命令。 所以我尝试了一种不同的方法:

  • 第一次运行: git fsck --unreachable | findstr "commit" git fsck --unreachable | findstr "commit"
  • 将输出复制到记事本
  • start cmd /k git show找到替换“unreachable commit”

会看起来像这样:

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)

可能不是最好的解决方案,但为我工作


要获取存储库中仍然存在,但无法再访问的存储列表,请执行以下操作:

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

如果您给藏了一个标题,请在命令末尾的-grep=WIP中用您的消息的一部分替换“WIP”,例如-grep=Tesselation

该命令针对“WIP” WIP on mybranch: [previous-commit-hash] Message of the previous commit.因为默认的stash提交消息的格式WIP on mybranch: [previous-commit-hash] Message of the previous commit.





git-stash