当在rebase操作期间意外跳过有用的提交时,是否有希望Git保留可以重新应用它的引用?
这是一个包含大量二进制文件的非交互式rebase,我使用git rebase --skip
进行了很长时间的快乐触发情绪,因此根本没有错误信息,只是一种糟糕的态度。
这似乎是一个硬盘崩溃的恢复方案,但不应该追逐幻像inode,应该有一种方法来过滤.git/objects
中丢失的树对象并让它们恢复活着。
答案 0 :(得分:4)
当您运行git rebase
(交互式或非交互式)时,git基本上会执行一系列cherry-pick
操作,以将原始提交链复制到新链。让我们使用o
作为原始提交,并为分支branch
的分支main
绘制提交图片段:
o1 - o2 - o3 - o4 <-- branch
/
..- * - x <-- main
现在,您可以运行git rebase
将所有旧的o
提交复制到新的n
提交,但基于x
,main
的提示,而不是基于*
,旧的合并基点。为了使它更像发生的事情,让我们意外地&#34;留下一个:
o1 - o2 - o3 - o4 <-- ???
/
..- * - x <-- main
\
n1 - n3 - n4 <-- branch
上面的???
标签表示指向或指向提交o4
的git引用(branch-name,tag-name或任何其他合适的标签)。 只要有一个指向他们的名字,所有旧提交仍然在那里。如果有没有名称,他们仍会坚持到git gc
清除它们(但你不希望这种情况发生,所以不要运行{{ 1}} :-))。
那么重要的问题是:&#34;我们(和git)可以使用哪些名称来查找git gc
?&#34;事实证明至少有两个:
o4
。 ORIG_HEAD
一个是最容易使用的,但该名称也被其他命令(例如ORIG_HEAD
)使用,因此您必须查看它是否仍然正确:< / p>
git merge
如果这为您提供了正确的链,请给自己一个更长久的名称,指向提交$ git log ORIG_HEAD
。这可以是分支名称(因此&#34;复活&#34;新名称下的旧分支),或标记名称,或者实际上任何其他名称,但分支和标记很容易:
o4
(你不 这样做,而且随着你对git越来越熟悉,你可以跳过这一步,但在此之前它可能是好事。)
如果$ git branch zombie ORIG_HEAD
遭到重击(例如,通过另一个rebase,或合并,或其他什么),该怎么办?好吧,那就是reflogs。
ORIG_HEAD
有一个reflog,默认情况下,每个分支名称都有另一个reflog。在这种情况下,要使用的是HEAD
:
branch
但是您可以使用$ git reflog branch
$ git log -g branch
来显示git reflog
的一个(这个更吵,这就是为什么只看HEAD
可能更好的原因):
branch
在所有输出中的某个地方,您应该能够找到提交$ git reflog
$ git log -g
。您可能会发现很多类似o4
的其他提交,这就是为什么o4
会有所帮助,因为它会让您找到真实的(或正确的)git log -g
。
无论如何,假设你最终想出了一个reflog风格&#34;相对的名字&#34; (例如o4
或branch@{1}
),您可以找到原始SHA-1或使用该相对名称再次复活branch@{yesterday}
的僵尸版本:
branch
或:
$ git branch zombie branch@{yesterday}
或其他什么。
所有这一切都会给你一个名字$ git branch zombie feedd0gf00d
,其中图表的图形中有三个问号。您仍然必须使用它来查找已删除的提交,在本例中为commit zombie
。您可以通过原始SHA-1(通过阅读o2
)找到它并重新重新绑定并拉入其中,或者选择它以将副本附加到git log
或其他任何内容。
如果您要做的只是将n4
设置回提交branch
,您甚至可以完全免除僵尸分支,只需在分支{{1}上执行o4
}}:
git reset --hard
或:
branch
请注意,$ git checkout branch # if needed
$ git reset --hard feedd0gf00d
之后的内容只是任何提交ID。 $ git reset --hard ORIG_HEAD
使reset --hard
删除工作树并将其替换为目标提交,而--hard
操作本身告诉git:&#34;使当前分支指向提交-ID我即将给你,不管它现在命名的分支 - 提示 - &#34;
换句话说,在reset
完成后发现您在制作reset
链时遗漏git rebase
,如果您立即o2
,git会更改此内容:< SUP> 1
n1 - n3 - n4
到此:
git reset --hard ORIG_HEAD
o1 - o2 - o3 - o4 <-- ORIG_HEAD
/
..- * - x <-- main
\
n1 - n3 - n4 <-- HEAD=branch
提交的 o1 - o2 - o3 - o4 <-- ORIG_HEAD, HEAD=branch
/
..- * - x <-- main
\
n1 - n3 - n4 [abandoned]
链实际上仍然在回购中,当然:在reflog中有一个指向[abandoned]
的名称!
(reflog条目最终会在30到90天之后失效,具体取决于尚未感兴趣的细节 - 一旦过期且没有名称可供查找{{1} }或n
或其他,然后 n4
将清理并删除它们。)
1 请注意,我已将n4
符号添加到此图表中,以指明您所在的分支。这个o4
的东西实际上是git跟踪你所依赖的分支的非常好的近似。在git gc
目录中,有一个名为HEAD=
的文件,该文件只包含当前分支的名称! 2 如果您在其中写入新名称文件,git改变了你在哪个分支上的想法(不改变任何其他内容)。这正是HEAD=
的作用:将新名称写入.git
。 (使用HEAD
添加更多操作:git reset --soft
然后更新索引/登台区域;并使用HEAD
添加更多:--mixed
然后清除工作目录内容用它们放入git reset
文件中的任何内容替换它们。)
2 在&#34;分离的HEAD&#34;模式,该文件包含当前提交的原始SHA-1,而不是当前分支的名称。事实上,这是&#34;在分支上的真正区别&#34;并且处于&#34;分离的HEAD&#34;模式。当git想要知道当前提交是时,它会查看文件--hard
。如果它有原始SHA-1,那就是答案。如果它有一个分支名称,git会读取分支名称以获取原始SHA-1。这是唯一允许的两个设置 - git reset
文件中没有任何其他设置。
答案 1 :(得分:1)
git reflog
适合你吗?我认为它应该仍然在垃圾收集器中,除非你运行git gc