git fsck combining --lost-found and --unreachable



我发现了许多关于git fsck的有趣帖子,所以我想对它们进行一些实验。首先,我在这个问题之前读到的所有来源:

  • 如何通过关键字在GIT存储库中找到无法访问的提交哈希?

  • git fsck:悬空与无法到达与丢失有何区别?

  • 获取所有git提交的列表,包括丢失的

我从这个回购开始:

* 9c7d1ea (HEAD -> test) f
* cd28884 e
| * 7b7bac0 (master) d
| * cab074f c
|/  
* d35af2c b
| * f907f39 r # unreferenced commit
|/
* 81d6675 a

其中CCD_ 2是从从CCD_ 4分离的CCD_。然后我想在test上重新设置master的基础,但我有一些未标记的更改,所以我做了:

git rebase --autostash test

获取(我没有显示r,但它仍然存在):

* caee68c (HEAD -> master) d
* 2e1cb7d c
* 9c7d1ea (test) f
* cd28884 e
* d35af2c b
* 81d6675 a

下一次运行:

$ git fsck
#...
dangling commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
#...
$ git fsck --unreachable
#...
unreachable commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
unreachable commit d8bb677ce0f6602f4ccad46123ee50f2bf6b5819 # stash index
#...
$ git fsck --lost-found
#...
dangling commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
dangling commit f907f39d41763accf6d64f4c736642c0120d5ae2 # r
#...

第一个问题

为什么只有--lost-found版本返回r提交?为什么rebase之前的cd没有显示在不可达的中?我以为我理解阅读相关问题的区别,但我显然遗漏了一些东西。我仍然有完整的reflog,但我想您不需要它,因为所有提交(与stash相关的提交除外)都被引用了。


我知道我应该再写一篇帖子,但第二个问题部分相关。出于好奇我尝试了:

$ git fsck --lost-found --unreachable
#...
unreachable commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
unreachable commit d8bb677ce0f6602f4ccad46123ee50f2bf6b5819 # stash index
unreachable commit f907f39d41763accf6d64f4c736642c0120d5ae2 # r
unreachable commit 7b7bac0608936a0bcc29267f68091de3466de1cf # c before rebase
unreachable commit cab074f2c9d63919c3fa59a2dd63ec874b0f0891 # d before rebase
#...

第二个问题

结合这两个选项,我得到了所有无法访问的提交(而不仅仅是--lost-found--unreachable的并集),这是非常出乎意料的。为什么它会这样?

其中有些确实令人费解,而且似乎没有正确的文档记录,但快速查看内置的/fsck.c可以发现,使用--lost-found:

  1. 开启--full
  2. 打开CCD_ 18

项目1不是特别有趣,因为--full现在默认是打开的,但文档确实应该指出r0禁用--no-full。第2项解释了其余的大部分内容;我对最后一部分有一个猜测[编辑:其余部分]。

请注意,当您运行时

git checkout master && git rebase --autostash test

这使得Git运行git stash push,它生成了一个由两个新提交组成的新存储。然后,Git像往常一样进行重基,将原始git log --all --decorate --oneline --graph输出中可见的cab074f7b7bac0提交复制到第二个输出中可见新的2e1cb7dcaee68c提交。

为什么只有--lost-found版本返回r提交?为什么再碱基之前的HEAD0和d没有显示在不可达的中?

假定提交仍在HEADreflog中。这使得它可以从引用访问——但由于--lost-found意味着--no-reflogs,所以这次它变得不可访问。cd的原始文件也是如此:它们可以通过来自HEAD的reflog和master的多个reflog条目访问。

结合这两个选项,我得到了所有无法访问的提交(而不仅仅是--lost-founda0的并集),这是非常出乎意料的。为什么它会这样?

这更令人费解[编辑:已解决;请参阅下文。]让我们按照git fsck命令的顺序运行这些命令:

  • fsck 1和fsck 2:两者都发现了autostash提交。这是因为git stash push将原始refs/stash复制到存储reflog中,因此refs/stash可以指向autostashw(工作树)提交。然后,隐含的git stash apply && git stash drop(git stash pop)应用了隐藏并将其丢弃,将stash@{1}条目移回refs/stash并删除隐藏reflog。因此,来自autostash的CCD_;悬挂";。它不在refs/stash中,甚至不在stashreflog中,因为git stash(ab)使用该reflog作为";隐藏堆栈";。然而,它确实指向来自autotash的i提交。

    然后,第一个fsck打印6387b70fe14f1ecb90e650faba5270128694613d并将其称为";悬挂";。这是被丢弃的w提交。第二个fsck--unreachable一起添加了d8bb677ce0f6602f4ccad46123ee50f2bf6b5819:相应的被丢弃的i提交。

  • fsck 3:r和重基提交在git fsck --unreachable下保持不可见,因为它们是从reflog中引用的。但现在,有了--lost-found,fsck不再关注通货再膨胀。我们应该看到autostashw提交、r提交和预重定基d,所有这些都是悬空的。[编辑:根据注释,这是错误的:w链接回id,因此这将隐藏d。]

    我们实际上看到了wr提交,但没有看到d提交为什么不呢这是我的猜测,但很容易测试您是否仍有设置:当您成功使用git rebase时,Git会创建或更新名为ORIG_HEAD的伪引用,以在rebase完成前记住提示提交的哈希ID。请注意,在成功移动一个分支的git reset之后,以及在可能将分支名称移动一段距离的任何其他操作(例如,快进合并)之后,使用相同的名称来记住ref的上一个值

    很明显,git fsck必须考虑所有各种*_HEAD伪引用作为可达性的起点。这也没有记录在案(这里甚至不完全清楚这是故意的——ref代码最近进行了一些相当大的返工,以支持替代的ref后端)

  • fsck 4,就在您的"第二个问题"部分之前:要么--unreachable关闭了伪引用包含,要么——我认为这更有可能——您在两者之间做了一些操作,触动了ORIG_HEAD,使其不再选择原始的预重基准d提交[edit]由于--unreachable列出了所有不可访问的提交,因此d可以从autostashw提交间接访问这一事实无关紧要,我们可以看到所有内容。

如果您想报告Git文档错误,fsck文档没有注意到--lost-found意味着--no-reflogs,那么您应该这样做。

相关内容

  • 没有找到相关文章

最新更新