如果在重新执行基准操作期间偶然跳过了有用的提交,是否有希望Git保留可以重新应用的引用?
这是一个具有许多二进制文件的非交互基础,使用,我花了很长时间来触发愉快的心情git rebase --skip,因此根本没有错误消息,只是糟糕的态度。
这似乎是硬盘崩溃的恢复方案,但与其追逐幻像inode,还不如采用一种方法来过滤掉内部丢失的树对象.git/objects并使它们恢复活动。
当您运行时git rebase(是否互动),git基本上会执行一系列cherry-pick操作以将您的原始提交链复制到新链中。让我们使用o原始提交,并为分支branch从分支出来绘制提交图片段main:
o1 - o2 - o3 - o4 <-- branch
/
..- * - x <-- main
Run Code Online (Sandbox Code Playgroud)
现在,您可以运行git rebase将所有旧o提交复制到新n提交,但是基于off x的尖端main,而不是基于off *的合并基础点。为了使它更像发生的事情,让我们“意外地”将其中一个排除在外:
o1 - o2 - o3 - o4 <-- ???
/
..- * - x <-- main
\
n1 - n3 - n4 <-- branch
Run Code Online (Sandbox Code Playgroud)
???上面的标签表示指向或指向commit的git参考(分支名称,标签名称或任何其他合适的标签)o4。 只要有一个指向它们的名称,您所有的旧提交都仍在其中。如果没有名字,它们仍然会停留直到git gc清除掉(但是您不希望这样发生,所以不要运行git gc:-))。
那么,重要的问题是:“我们(和git)可以使用什么名称o4?” 事实证明,至少有两个:
ORIG_HEAD。在ORIG_HEAD一个是最容易使用,但该名称也使用其他命令(git merge例如),所以你必须看到,如果它仍然是正确的:
$ git log ORIG_HEAD
Run Code Online (Sandbox Code Playgroud)
如果那给您正确的链,请给自己一个更永久的名称,指向commit o4。这可以是分支名称(因此,您可以用新名称“恢复”旧分支),标签名称,或者实际上是其他名称,但branch和tag很简单:
$ git branch zombie ORIG_HEAD
Run Code Online (Sandbox Code Playgroud)
(你不会有这样做,而当你获得更舒适的使用Git,你可以跳过这一步,但它可能是好做的再说吧。)
如果ORIG_HEAD遭到重击(例如,被另一个变基,合并,或其他原因)怎么办?好吧,那么这里有更新。
有一个reflog HEAD,默认情况下,每个分支名称都有另一个reflog。在这种情况下,将使用以下引用日志branch:
$ git reflog branch
$ git log -g branch
Run Code Online (Sandbox Code Playgroud)
但是您可以仅使用它git reflog来显示HEAD(这比较吵,这就是为什么只看一个branch可能更好):
$ git reflog
$ git log -g
Run Code Online (Sandbox Code Playgroud)
在所有输出的某个位置,您应该能够找到commit o4。您可能会发现许多其他类似的提交o4,这就是为什么git log -g会有所帮助的原因,因为它将使您找到真正的(或正确的)提交o4。
无论如何,假设您最终使用了reflog样式的“相对名称”(如branch@{1}或branch@{yesterday}),则可以找到原始SHA-1或使用该相对名称再次使僵尸版本复活branch:
$ git branch zombie branch@{yesterday}
Run Code Online (Sandbox Code Playgroud)
要么:
$ git branch zombie feedd0gf00d
Run Code Online (Sandbox Code Playgroud)
管他呢。
所有这一切都为您提供了一个名称,zombie在该图形的绘图中有三个问号。您仍然必须使用它来查找已删除的提交,在本例中为commit o2。您可以通过原始SHA-1(通过阅读git log)找到它,然后重新调整其基数并将其拉入其中,或对其进行挑选,以将副本附加到n4,或其他方式。
如果您想做的所有事情都branch重新设置为commit o4,那么您甚至可以完全省去僵尸分支,git reset --hard而在分支上做一会儿branch:
$ git checkout branch # if needed
$ git reset --hard feedd0gf00d
Run Code Online (Sandbox Code Playgroud)
要么:
$ git reset --hard ORIG_HEAD
Run Code Online (Sandbox Code Playgroud)
注意,后面的东西reset --hard就是任何提交ID。该--hard品牌reset消灭你的工作树,并与目标替代它提交,而reset行动本身告诉git的:“使当前分支指向提交-ID我正要给你,不管任何的分支尖端提交它现在就命名。”
换句话说,git rebase完成后发现o2制作n1 - n3 - n4链时被遗漏了,如果立即使用git reset --hard ORIG_HEAD,git会更改:1
o1 - o2 - o3 - o4 <-- ORIG_HEAD
/
..- * - x <-- main
\
n1 - n3 - n4 <-- HEAD=branch
Run Code Online (Sandbox Code Playgroud)
对此:
o1 - o2 - o3 - o4 <-- ORIG_HEAD, HEAD=branch
/
..- * - x <-- main
\
n1 - n3 - n4 [abandoned]
Run Code Online (Sandbox Code Playgroud)
该[abandoned]链n提交实际上仍然是在回购,当然:有指向一个名字n4在reflogs!
(引用日志的条目最终到期,在默认情况下,经过30到90天,这取决于细节尚未有趣的,而一旦过期,并且没有任何名称由发现n4或o4也好,然后 git gc将清理并删除它们。)
1请注意,我已经在HEAD=该图中添加了表示法,以指示您所在的分支。这些HEAD=东西实际上是git如何跟踪您所在的分支的一个很好的近似。在.git目录中,有一个名为的文件HEAD,该文件仅包含当前分支的名称!2 如果您在文件中写了一个新名称,则git会更改其对您所在的分支的想法(不更改其他任何内容)。就是git reset --soft这样:将新名称写入HEAD。(使用--mixed会增加一些操作:git reset然后更新索引/临时区域;使用--hard会增加更多操作:git reset然后清除工作目录中的内容,将其替换为放入目录中的任何内容。HEAD 文件。)
2在“分离式HEAD”模式下,该文件包含当前提交的原始SHA-1 ,而不是当前分支的名称。实际上,这是“在分支上”和处于“分离头”模式之间的真正区别。当git想知道当前的提交是什么的时候,它会看文件HEAD。如果它具有原始的SHA-1,那就是答案。如果它具有分支名称,则git读取分支名称以获取原始SHA-1。这些是仅有的两个允许的设置- HEAD文件中应无其他内容。
| 归档时间: |
|
| 查看次数: |
1030 次 |
| 最近记录: |