为什么父母存储在git笔记中?

时间:2013-06-10 06:49:18

标签: git git-svn internals git-notes

git store指出的方式:

  • Git仅为单个命名空间的每次提交存储一个注释。一个人可以有多个名称空间默认命名空间是commit。
  • .git / refs / notes /包含一个哈希(例如MainHash_2),它是一个树对象。无论何时创建注释,哈希都会发生变化。
  • 此树对象包含两个以上的哈希值。一个到另一个树结构(注释树结构,比如说NOTES_2)和一个到父树对象(创建这个注释之前的.git / refs / notes /中的一个,比如MainHash_1)< / LI>
  • 备注树结构包含每个备注的一个条目。每个条目都有两个哈希:一个用于记录内容,另一个用于指定提交。

如第三点所述,父母存储的原因是什么?由于这个父类(它的类型与第二点中提到的类型相同)也包含另一个树,每个音符包含一个条目。

假设您目前有三个音符。 MainHash_2包含NOTES_2的哈希值,其中包含每个注释的三个条目。 MainHash_1包含NOTES_1的哈希值,其中包含两个条目(除了现在创建的所有其他注释)。 为什么要两次存储这两个条目等等?

2 个答案:

答案 0 :(得分:2)

仅仅因为注释命名空间在git中并不特别,它们只是具有完整历史记录的普通分支。你可以做到

git checkout notes/commits

与其他任何分支一样使用您的笔记,例如你可以做到

git log notes/commits

查看笔记的提交日志。这样您就可以跟踪笔记的所有更改。

你这么说:

  

.git/refs/notes/commits包含一个哈希(例如MainHash_2),它是对象。

它不是对象,它是提交。就像在.git/refs/heads/master中一样。您可以使用git cat-file -t <hash>

进行检查

答案 1 :(得分:0)

git notescommit 73f77b9, Git v1.6.6-rc0中引入。
扇出的概念是在2010年2月与commit 73f77b9一起在Git v1.7.1-rc0中引入的,目的是在{{1 }}。

.git/refs/notes/commits”变量的值:

  • fanout:无扇出(所有笔记都直接存储在根笔记树中)
  • 01扇出
  • 2/382扇出
  • 2/2/363扇出

在Git 2.25.2(2020年3月)中,用于自动缩小笔记树中的扇出的代码存在一个错误的错误,该错误已被杀死。

请参见commit dbc2747commit e1c5253Johan Herland (jherland)(2020年2月3日)。
(由Junio C Hamano -- gitster --commit 8833260中合并,2020年2月14日)

t3305:更仔细,更可靠地检查笔记扇出状态

简而言之,在此补丁之前,请使用以下测试脚本:

  • 创建许多笔记
  • 验证笔记树中的所有笔记的扇出度为1
  • 删除大部分笔记
  • 验证注释树中的注释现在扇出为0

扇出验证仅进行两次:创建所有便笺后,以及删除大部分便笺。

此补丁通过检查2/2/2/34 _添加/删除音符后的扇出来增强测试:我们断言,在添加音符时,从扇出0-> 1的切换仅发生一次(并且该音符遍及了整个音符)树)。同样,我们断言在删除笔记时,从扇出1-> 0的切换仅发生一次。

另外,我们将移除后剩余的音符数量从50个减少到15个,以确保不考虑外部因素(1)持续进行扇出1-> 0过渡。

(1):当前(具有SHA1哈希函数和测试环境的确定性对象ID)注释代码中的扇出启发式碰巧从109个注释的0-> 1切换为1- > 59个笔记时为0
但是,更改哈希函数或其他外部因素将改变这些数字,并且理论上后者可能低至15。
有关更多详细信息,请参见the discussion

并且:

notes.c:解决了减少音符扇出时出现的一对一错误

如上一次提交中所述,注释代码中扇出启发式的性质使我们增加或减少注释扇出的确切点随要注释的对象而变化。
由于测试环境生成的对象ID是确定性的(通过设计),因此t3305生成和测试的注释始终相同,因此,从一次运行到下一次运行,我们碰巧看到相同的扇出行为。

巧合的是,如果我们要稍微改变测试环境(例如,在正确启动t3305测试之前在不相关的分支上进行测试提交),我们不仅会看到扇出切换发生在不同的点,而且我们也设法在注释代码中触发 bug ,其中扇出_each开关未在注释树上统一应用,而是生成了一个注释树,如下所示:

1 -> 0

当我们用新减少的扇出写出笔记树时,便会发生此错误,并且笔记树包含未扩展的子树,由于扇出减少,这些子树应合并到父树中)

在内部注释16树结构中恰好位于 even 级别的

子树(换句话说:上面示例中其路径-“ ... bdeafb301e44b0e4db0f738a2d2a7beefdb70b70 bff2d39b4f7122bd4c5caee3de353a774d1e632a d3/8ec8f851adf470131178085bfbaab4b12ad2a7 e0b173960431a3e692ae929736df3c9b73a11d5b eb3c3aede523d729990ac25c62a93eb47c21e2e3 ... ”的子树是唯一的)在第一个半字节中-即,没有其他以“ {d3”开头的音符路径被解压缩为树写输出的一部分。
该错误将在后续的笔记树中重复出现,直到子树被迫解压缩为止。在t3305中,只有当d音符本身从树中删除时,这种情况才会发生。

错误并不严重(不会丢失任何信息,并且notes代码能够读取/解码此树并正确地对其进行操作),但这仍然是当前实现中的错误,应予以修复。

也就是说,解决一次性错误并非没有复杂之处:

我们必须考虑到d38ec8f8的{​​{1}}调用(现在这样做是为了在我们写出笔记树时正确地解包子树)可能最终会插入未打包的非笔记进入结构load_subtree()所拥有的for_each_note_helper()条目的链接列表中。
由于我们正在写出笔记树,因此该链表目前正在被non_note遍历。
未包装的非注释必须插入我们写出的最后一个非注释与要写入的下一个非注释之间。
因此,我们不能简单地握住notes_tree来写入结构write_each_non_note_until()(因为我们随后会静默地跳过这些新插入的音符),而必须始终遵循最后一个非{ -注意我们写的。 (这部分已被t3304中的现有测试捕获。)