我经常使用git stash
和git stash pop
来保存和恢复工作树中的更改。昨天我的工作树上有一些变化,我已经藏起来了,然后我对工作树做了更多改动。我想回去查看昨天的隐藏更改,但git stash pop
似乎删除了对相关提交的所有引用。
我知道如果我使用git stash
,那么 .git / refs / stash包含用于创建存储的提交的引用。并且 .git / logs / refs / stash包含整个存储。但那些引用在git stash pop
之后消失了。我知道提交仍然存放在我的存储库中,但我不知道它是什么。
有没有一种简单的方法可以恢复昨天的隐藏提交引用?
请注意,这对我来说并不重要,因为我每天都有备份,可以回到昨天的工作树来获取我的更改。我问,因为必须有一个更简单的方法!
答案 0 :(得分:2412)
一旦你知道你删除的藏匿提交的哈希值,就可以将它作为一个存储点使用:
git stash apply $stash_hash
或者,您可以使用
为其创建单独的分支git branch recovered $stash_hash
之后,您可以使用所有常规工具执行任何操作。当你完成后,只需把树枝吹走。
如果您刚刚弹出它且终端仍处于打开状态,您将still have the hash value printed by git stash pop
on screen(谢谢,Dolda)。
否则,你可以在Linux,Unix或Git Bash for Windows中找到它:
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
...或使用Powershell for Windows:
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
这将向您显示提交图提示中的所有提交,这些提交不再从任何分支或标记引用 - 每个丢失的提交(包括您创建的每个存储提交)都将位于该图中的某个位置。 / p>
找到所需存储提交的最简单方法可能是将该列表传递给gitk
:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
...如果使用Powershell for Windows,请参阅the answer from emragins。
这将启动一个存储库浏览器,显示存储库中的每个提交,无论它是否可访问。
如果您希望通过单独的GUI应用程序在控制台上使用漂亮的图形,则可以使用gitk
之类的内容替换git log --graph --oneline --decorate
。
要发现存储提交,请查找此表单的提交消息:
WIP somebranch : commithash一些旧提交消息
注意:如果您在执行git stash
时未提供消息,则提交消息将仅采用此格式(以“WIP on”开头)。
答案 1 :(得分:666)
如果您没有关闭终端,只需查看git stash pop
的输出,您将获得已删除存储的对象ID。通常看起来像这样:
$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)
(注意git stash drop
也会生成相同的行。)
要获得回收,只需运行git branch tmp 2cae03e
,您就可以将其作为分支。要将其转换为存储,请运行:
git stash apply tmp
git stash
将它作为分支也可以让你自由地操纵它;例如,樱桃挑选或合并它。
答案 2 :(得分:252)
只是想提及已接受解决方案的这一补充。我第一次尝试这种方法时并不是很明显(也许应该是这样),但是要从哈希值中应用存储,只需使用“git stash apply”:
$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219
当我刚接触git时,这对我来说并不清楚,我正在尝试“git show”,“git apply”,“patch”等的不同组合。
答案 3 :(得分:79)
获取仍在存储库中但仍无法访问的存储列表:
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
如果您为保管提供了标题,请将命令末尾的-grep=WIP
中的“WIP”替换为部分信息,例如: -grep=Tesselation
。
该命令正在为“WIP”进行grepping,因为存储的默认提交消息采用WIP on mybranch: [previous-commit-hash] Message of the previous commit.
答案 4 :(得分:71)
我刚刚构建了一个命令,帮助我找到丢失的存储提交:
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 / 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
答案 5 :(得分:38)
git fsck --unreachable | grep commit
应该显示sha1,尽管它返回的列表可能非常大。 git show <sha1>
将显示它是否是您想要的提交。
git cherry-pick -m 1 <sha1>
会将提交合并到当前分支上。
答案 6 :(得分:27)
如果你想要重建一个丢失的藏匿处,你需要先找到你丢失的藏匿的哈希值。
正如Aristotle Pagaltzis建议git fsck
应该帮助你。
我个人使用我的log-all
别名来向我展示每次提交(可恢复的提交)以更好地了解情况:
git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)
如果您只查看“在线开启”消息,则可以进行更快速的搜索。
一旦你知道你的sha1,你只需更改你的存储reflog以添加旧的存储:
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
答案 7 :(得分:21)
使用gitk等效的Windows PowerShell:
gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })
在一个管道中执行此操作可能是一种更有效的方法,但这可以完成这项工作。
答案 8 :(得分:16)
我喜欢亚里士多德的方法,但不喜欢使用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
答案 9 :(得分:12)
在使用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}
时希望这可以帮助某人快速
答案 10 :(得分:11)
为什么人们会问这个问题?因为他们还不了解或了解reflog。
这个问题的大多数答案给出了长命令,几乎没有人会记得。所以人们进入这个问题并复制粘贴他们认为他们需要的东西,并且几乎立即忘记它。
我会建议每个人只要查看reflog(git reflog)就可以了解这个问题。一旦你看到所有提交的列表,有一百种方法可以找出你正在寻找的提交,并挑选它或从中创建一个分支。在这个过程中,您将了解各种基本git命令的reflog和有用选项。
答案 11 :(得分: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
然后,您将获得一个接一个显示的哈希的所有差异。按'q'进入下一个差异。
答案 12 :(得分:9)
亚里士多德接受的答案将显示所有可访问的提交,包括非存储类提交。滤除噪音:
The Android Gradle Plugin and Gradle
Android Gradle Plugin Requires Gradle
1.0.0 - 1.1.3 2.2.1 - 2.3
1.2.0 - 1.3.1 2.2.1 - 2.9
1.5.0 2.2.1+ 2.2.1 - 2.13
2.0.0 - 2.1.2 2.10 - 2.13
2.1.3 - 2.2.3 2.14.1+
2.3.0+ 3.3+
3.0.0+ 4.1+
3.1.0+ 4.4+
3.2.0 - 3.2.1 4.6+
3.3.0 - 3.3.1 4.10.1+
这将仅包含具有3个父提交(保存将具有)的提交,并且其消息包括“WIP on”。
请注意,如果您使用邮件(例如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
)保存了存储空间,则会覆盖默认的“WIP on ...”消息。
您可以显示有关每次提交的更多信息,例如显示提交消息,或将其传递给git stash save "My newly created stash"
:
git stash show
答案 13 :(得分:9)
我无法在一个简单的命令窗口(在我的案例中为Windows 7)中获得在Windows上工作的任何答案。 awk
,grep
和Select-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
git stash apply (your hash)
可能不是最好的解决方案,但对我有用
答案 14 :(得分:9)
您可以通过在终端中编写此命令列出所有无法访问的提交 -
git fsck --unreachable
检查无法访问的提交哈希 -
git show hash
如果你找到了藏匿物品,最后申请 -
git stash apply hash
答案 15 :(得分:4)
我来这里寻找的是如何实际获得藏匿,无论我检查了什么。特别是,我藏了些东西,然后检查了一个旧的版本,然后加油,但是那个藏匿处在那个早期的时间点是无操作的,所以藏匿物消失了;我不能只做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.
回想起来,我本应该使用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.
答案 16 :(得分:4)
使用以下步骤恢复它:
识别已删除的隐藏哈希码:
gitk --all $(git fsck --no-reflog | awk'/ dangling commit / {print $ 3}')
Cherry Pick the Stash:
git cherry-pick -m 1 $ stash_hash_code
解决冲突(如果有):
git mergetool
此外,如果您使用的是gerrit,则可能会遇到提交消息的问题。请在遵循下一个备选方案之前隐藏您的更改:
答案 17 :(得分:4)
我最喜欢的是这种单线纸:
git log --oneline $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )
这基本上与this answer相同,但是要简短得多。当然,您仍然可以添加--graph
以获得树状显示。
在列表中找到提交后,请使用
git stash apply THE_COMMIT_HASH_FOUND
对我来说,使用--no-reflogs
确实可以显示丢失的存储项,但是--unreachable
(在其他许多答案中都可以找到)却没有。
在Windows下,在git bash上运行它。
信用:以上命令的详细信息取自https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf
答案 18 :(得分:4)
您可以通过2个简单的步骤实现此目标
列出丢失的存储 ->对所有垃圾都被丢弃的项目运行此命令:
git fsck-无法访问| grep commit |切-d''-f3 | xargs git日志 -合并-禁止行走
将丢失的存储空间发回-> 让我们使用第二个存储的提交哈希:
git update-ref refs / stash 4b3fc45c94caadcc87d783064624585c194f4be8 -m “我的藏匿的东西”
答案 19 :(得分:2)
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP
试试这个
答案 20 :(得分:0)
要查看终端中的提交,只过滤我们可以使用的那些我们关心的:
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}' )
这是基于 Aristotle Pagaltzis 的回答。
答案 21 :(得分:-2)
我确实不小心删除了GitUP应用程序中的存储。只需按Ctrl + Z即可撤消。
也许对某人有帮助;)