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

Gre*_*ill 1617 git recovery git-stash

我经常使用git stashgit stash pop保存和恢复工作树中的更改.昨天我的工作树上有一些变化,我已经藏起来了,然后我对工作树做了更多改动.我想回去查看昨天发生的变化,但git stash pop似乎删除了对相关提交的所有引用.

我知道如果我使用git stash那么.git/refs/stash包含用于创建存储的提交的引用.而.git/logs/refs/stash包含整个存储.但那些参考文献已经消失了git stash pop.我知道提交仍然在我的存储库中,但我不知道它是什么.

有没有一种简单的方法来恢复昨天的隐藏提交引用?

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

Ari*_*zis 2607

一旦你知道你删除的存储提交的哈希值,你可以将它作为存储应用:

git stash apply $stash_hash
Run Code Online (Sandbox Code Playgroud)

或者,您可以为其创建单独的分支

git branch recovered $stash_hash
Run Code Online (Sandbox Code Playgroud)

之后,您可以使用所有常规工具执行任何操作.当你完成后,只需将树枝吹走.

找到哈希

如果您刚刚弹出它并且终端仍然打开,您仍然会git stash pop在屏幕上打印哈希值(谢谢,Dolda).

否则,你可以在Linux,Unix或Git Bash for Windows中找到它:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'
Run Code Online (Sandbox Code Playgroud)

...或者使用Powershell for Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
Run Code Online (Sandbox Code Playgroud)

这将向您显示提交图提示中的所有提交,这些提交不再从任何分支或标记引用 - 每个丢失的提交(包括您创建的每个存储提交)都将位于该图中的某个位置.

找到所需存储提交的最简单方法可能是将该列表传递给gitk:

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

...或者如果使用Powershell for Windows,请查看emragins的答案.

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

如果您喜欢在控制台上通过单独的GUI应用程序使用漂亮的图形,则可以替换gitkgit log --graph --oneline --decorate.

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

        在somebranch上的 WIP :commithash一些旧的提交消息

注意:如果您没有提供消息,则提交消息将仅以此形式(以"WIP on"开头)git stash.

  • 杰德尔把话说出了我的话.这篇文章保存了我的工作:)我只想添加 - 记住你工作的日期,无论你丢失了什么,都可以更轻松地浏览gitk以寻找你想要的东西. (43认同)
  • `git stash apply {ref}` 恢复了一个丢弃的 stash!`git` 太棒了,应该是非法的! (10认同)
  • 如果你知道什么时候发生了丢弃,你可以通过增加时间来使用这个单行来获取悬空提交列表:`git fsck --no-reflog | awk'/ dangling commit/{print $ 3}'| xargs -L 1 git --no-pager show -s --format ="%ci%H"| 排序`最后一个条目可能就是你要"存储申请"的条目. (9认同)
  • 值得一提的是,如果在存储时没有提供自己的消息(即通过执行`git stash save"<message>"`),提交消息将只有字符串"WIP". (5认同)
  • @Codey:因为PowerShell.我不知道MsysGit是否附带了AWK二进制文件.谷歌搜索告诉我像'%{$ _.分裂('')[2]; ``应该在PowerShell中的`awk`命令中执行相当于`{print $ 3}`的操作,但我没有Windows系统来测试它,你还需要一个等价的`/ dangling commit /`部分.无论如何,只需运行`git fsck --no-reflog`并查看输出.你想要"悬挂提交<commitID>"行的哈希. (3认同)
  • 你刚刚节省了我几个小时的工作时间,我刚刚弹出了一个存储,并意外地写了“git checkout .”而不是“git reset”。哈哈,在那之后我查看了“git reflog”,发现存储并没有在那里创建引用。 .我很绝望,直到找到这个答案,真的谢谢! (3认同)

Dol*_*000 685

如果您没有关闭终端,只需查看输出git stash pop,您将获得已删除存储的对象ID.它通常看起来像这样:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
Run Code Online (Sandbox Code Playgroud)

(注意,git stash drop也会生成相同的行.)

为了获得那些存储,只需运行git branch tmp 2cae03e,你就可以将它作为一个分支.要将其转换为存储,请运行:

git stash apply tmp
git stash
Run Code Online (Sandbox Code Playgroud)

将它作为分支也允许您自由地操纵它; 例如,樱桃挑选或合并它.

  • 您也可以执行`git stash apply commitid`然后`git stash`来获取新的存储. (53认同)
  • 请注意,如果git自动合并存储并且存在冲突,则不会向您显示哈希. (32认同)
  • @James:再说一次,如果这些冲突是运行`git stash pop`的结果,它也不会丢弃存储,所以这通常不是问题. (30认同)
  • 这也适用于恢复"git stash drop" (4认同)
  • 我的 git stash pop 输出中没有 SHA。:( (3认同)
  • @Honey:这就是`git stash pop` 的重点。如果你想在不删除它的情况下应用 stash,请改用 `git stash apply`。此外,如果您想将更改应用于多个分支,您也可以选择提交。 (2认同)
  • @MatthewFlaschen,您还可以使用“git stash store commitid”恢复旧的存储。这样做的优点是您的工作目录不会被触及,并且原始存储的日期会被保留。 (2认同)

Wad*_*ade 259

只是想提到对已接受的解决方案的这一补充.我第一次尝试这种方法时并不是很明显(也许应该是这样),但是要从哈希值中应用存储,只需使用"git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
Run Code Online (Sandbox Code Playgroud)

当我刚接触git时,这对我来说并不清楚,我正在尝试"git show","git apply","patch"等的不同组合.

  • 请注意,这会将(存储!)存储应用于当前工作树.如果树是脏的,您可能要先使用临时分支或存储,从SHA-1应用存储,再次存储,然后弹出第二个到最后一个存储(称为存储@ {1}). (2认同)

Sen*_*mar 96

要获取仍在存储库中但不再可访问的存储列表:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
Run Code Online (Sandbox Code Playgroud)

如果您为藏匿物提供了标题,请将-grep=WIP命令末尾的"WIP"替换为消息的一部分,例如-grep=Tesselation.

该命令正在为"WIP"进行grepping,因为存储的默认提交消息在表单中 WIP on mybranch: [previous-commit-hash] Message of the previous commit.

  • echo 'git fsck --无法访问 | grep 提交 | 切 -d" " -f3 | xargs git log --merges --no-walk --grep=WIP' &gt;/usr/local/bin/git-stashlog; chmod a+rx /usr/local/bin/git-stashlog # git stashlog (2认同)
  • 这有助于找到丢失的提交而不是接受的答案!当您找到提交时,使用“git stash apply &lt;commit_hash&gt;”应用它 (2认同)
  • 如果操作系统采用其他语言,则可能会失败。例如,在法语中,我们必须使用 `cut -d" " -f4` 来匹配“object commit inatteignable 12f1d8d92b703b220c37403d0eb83dba5e273551”中的 sha1 (2认同)

Gre*_*ill 72

我刚刚构建了一个命令,帮助我找到丢失的存储提交:

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
Run Code Online (Sandbox Code Playgroud)

这将列出.git/objects树中的所有对象,找到类型为commit的对象,然后显示每个对象的摘要.从这一点来看,只需查看提交内容即可找到合适的"WIP on work:6a9bb2"("work"是我的分支,619bb2是最近的提交).

我注意到,如果我使用"git stash apply"而不是"git stash pop"我不会遇到这个问题,如果我使用"git stash save message ",那么提交可能更容易找到.

更新:根据内森的想法,这变得更短:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
Run Code Online (Sandbox Code Playgroud)


Nat*_*nes 38

git fsck --unreachable | grep commit应该显示sha1,虽然它返回的列表可能非常大.git show <sha1>将显示它是否是您想要的提交.

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


Col*_*ert 30

如果你想要重建一个丢失的存储,你需要先找到丢失的存储的哈希值.

正如亚里士多德Pagaltzis所建议的,git fsck应该帮助你.

就个人而言,我使用我的log-all别名向我展示每次提交(可恢复的提交)以更好地了解情况:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
Run Code Online (Sandbox Code Playgroud)

如果您只查看"WIP on"消息,则可以进行更快速的搜索.

一旦你知道你的sha1,你只需更改你的存储reflog以添加旧的存储:

git update-ref refs/stash ed6721d
Run Code Online (Sandbox Code Playgroud)

你可能更愿意有一个相关的消息,所以a -m

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

你甚至想用它作为别名:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
Run Code Online (Sandbox Code Playgroud)

  • 然而`-d\\`应该是`-d\`(或者更清晰的`-d' '`) (2认同)

emr*_*ins 27

使用gitk等效的Windows PowerShell:

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

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

  • 我非常感谢你的回答 (3认同)

Adr*_*n W 17

我最喜欢的是这个单线:

git log --oneline  $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )
Run Code Online (Sandbox Code Playgroud)

这与此答案的想法基本相同,但要短得多。当然,您仍然可以添加--graph以获得树状显示。

当您在列表中找到提交时,使用

git stash apply THE_COMMIT_HASH_FOUND
Run Code Online (Sandbox Code Playgroud)

对我来说,使用--no-reflogs确实显示了丢失的存储条目,但是--unreachable(在许多其他答案中发现)没有。

当你在 Windows 下时,在 git bash 上运行它。

积分:上述命令的详细信息取自https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf


Sha*_*ssy 16

我喜欢亚里士多德的方法,但不喜欢使用GITK ......因为我习惯于从命令行使用GIT.

相反,我接受了悬挂提交并将代码输出到DIFF文件以供我在代码编辑器中查看.

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

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

然后就用吧

git stash apply ad38abbf76e26c803b27a6079348192d32f52219
Run Code Online (Sandbox Code Playgroud)


Viv*_*mar 14

您可以通过在终端中写入此命令来列出所有无法访问的提交 -

git fsck --unreachable
Run Code Online (Sandbox Code Playgroud)

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

git show hash
Run Code Online (Sandbox Code Playgroud)

如果你发现藏匿物品,最后申请 -

git stash apply hash
Run Code Online (Sandbox Code Playgroud)


Can*_*cim 13

在使用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时,应用{commit-id}

希望这可以帮助别人


Rob*_*byD 12

为什么人们会问这个问题?因为他们还不了解或了解reflog.

这个问题的大多数答案给出了长命令,几乎没有人会记得.所以人们进入这个问题并复制粘贴他们认为他们需要的东西并且几乎立即忘记它.

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

  • 嗨罗比。如果您正在工作,偏离了方向,需要从几周前停下的地方继续,却发现找不到您隐藏的工作,那么这很重要——它可能在您的其他东西中的某个地方丢失了。在做。如果引用日志是最近的历史记录,那么它就很好,但对于很长的时间间隔就不是这样了。 (2认同)

Phi*_*hil 10

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

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


Koe*_*oen 10

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

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


ll2*_*2ll 10

这对我(2022 年)有用,可以从 Windows 环境恢复 git 中意外删除的存储。

这些步骤概述了如何恢复任何已删除的 git 存储或分支(假设它尚未被垃圾收集永久删除)。

  1. 导航到您的项目所在的目录。

  2. 输入命令:git fsck --no-reflogs | find "dangling commit" 在此输入图像描述

  3. 将出现悬空提交的哈希列表。这些将包含已删除的分支和存储。首先复制并粘贴列表末尾附近的哈希值以查找您的存储或分支。例如,使用命令:git log -1 [hash]

  4. 如果相应的哈希值与您尝试恢复的内容匹配,请使用以下命令来恢复它” git stash apply [hash]

  • “悬挂提交”没有这样的文件或目录 (3认同)

小智 9

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

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
Run Code Online (Sandbox Code Playgroud)

这将只包括具有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
Run Code Online (Sandbox Code Playgroud)


Abh*_*bhi 8

您可以通过 2 个简单的步骤实现这一目标

  1. 列出丢失的 stashs --> 为所有 stash 都被丢弃的项目运行此命令:

    git fsck --unreachable | grep 提交 | 剪切 -d ' ' -f3 | xargs git log --merges --no-walk

  2. 将丢失的存储发送回它的来源 --> 让我们使用第二个存储的提交哈希:

    git update-ref refs/stash 4b3fc45c94caadcc87d783064624585c194f4be8 -m“我恢复的藏匿处”


Tre*_*iño 6

要在终端中查看提交,只过滤我们关心的提交,我们可以使用:

git log --oneline --all --grep="^WIP on .*: [a-f0-9]\+" --grep="^On [^ ]*:" --grep="^index on [^ ]*:" $( env LANG=C git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
Run Code Online (Sandbox Code Playgroud)

这是基于亚里士多德帕加尔齐斯的回答。


Cha*_*ark 6

仅查看存储提交、它们附加的位置以及它们的内容

结果样本

Checking object directories: 100% (256/256), done.
2022-08-31 10:20:46 +0900 8d02f61 WIP on master: 243b594 add css
A       favicon.ico
Run Code Online (Sandbox Code Playgroud)

命令

git fsck --dangling | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ct %h" | sort | awk '{print $2}' | { while read hash; do status=$(git stash show $hash --name-status 2>/dev/null); if (( $? == 0 )); then git show $hash -s --format="%C(green)%ci %C(yellow)%h %C(blue)%B"; echo "$status"; fi; done; }
Run Code Online (Sandbox Code Playgroud)
  • 要查看完整的哈希值,请更改%h%H
  • 为了减少时间,tail fsck之类的git fsck --dangling | tail -100 | awk ...

回收样品 在此输入图像描述


Ben*_*Ben 5

我来这里寻找的是如何真正取回藏匿的东西,无论我检查了什么。特别是,我隐藏了一些东西,然后签出旧版本,然后弹出它,但在那个较早的时间点,隐藏的内容是无操作的,所以隐藏的消失了;我不能只是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.
Run Code Online (Sandbox Code Playgroud)

回想起来,我应该使用git stash applynot 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.
Run Code Online (Sandbox Code Playgroud)


Abh*_*eet 5

使用以下步骤恢复它:

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

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

  2. 樱桃挑选藏品:

    gitcherry-pick -m 1 $stash_hash_code

  3. 使用以下方法解决冲突:

    git合并工具

此外,如果您使用 gerrit,您可能会遇到提交消息的问题。在遵循下一个替代方案之前,请存储您的更改:

  1. 使用硬重置到以前的提交,然后重新提交此更改。
  2. 您还可以隐藏更改、重新设置基准和重新提交。