繁体   English   中英

git 如何从 packfiles 重新创建 deltified 对象?

[英]How does git recreate deltified objects from packfiles?

git如何解析packfile? 我似乎没有找到任何信息的一个关键步骤是 git 如何处理包文件中的 deltified 对象。 我发现的一个很好的资源是 git 文档,我再也找不到了。 这里有一个类似的副本。 我知道 git 会压缩它保存在对象目录中的各种数据,例如提交、树、blob 等,还有 Delta 对象,其中基础数据以某种方式与 delta 数据连接。 以下是object 类型的列表:OBJ_COMMIT、OBJ_TREE、OBJ_BLOB、OBJ_TAG、OBJ_OFS_DELTA、OBJ_REF_DELTA。 我也知道有两种类型的操作,即复制和插入,但我不清楚这些操作如何从包文件中重建修改后的文件。

我还在这里找到了一个相当不错的指南。

说,我有一个 OBJ_REF_DELTA object 坐在包文件的某个地方。 在该包文件中,我将能够从前 20 个字节解析基本 object (并且可能通过存储在索引文件或其他东西中的偏移量在包文件中找到它)。 然后是 delta 的 zlib 压缩数据。 解压后的数据是什么样子的。 这些是复制片段还是插入片段,或两者兼而有之? 它说:

增量以源长度和目标长度开始,都编码为可变长度整数,这对于错误检查很有用,但不是必需的。 在此之后,有一系列指令,可能是“复制”(MSB = 1)或“插入”(MSB = 0)。

通过增量开始,它们是否意味着基础 object 的 ref 之后的压缩数据? 不,因为他们说复制指令用于从基础 object 复制:

复制指令表示我们应该将一个连续的字节块从基础 object 复制到 output。 执行此操作需要两个数字:要复制的第一个字节的位置(偏移量)和要复制的字节数。 这些在每条复制指令之后存储为 little-endian 可变长度整数; 但是,它们的内容被压缩了。

那么复制和插入指令实际上在哪里呢? 为什么没有删除选项。 我了解到 delta 不是 diff,所以也许这意味着我添加的文件不是 delta,而是 delta 是根据存储为 blob 或其他东西的两个文件计算得出的,并且 delta 只能有副本并插入,不删除。 那是对的吗?

技术文档位于 Git 存储库中,位于Documentation/technical下。

说,我有一个 OBJ_REF_DELTA object 坐在包文件的某个地方。 在该包文件中,我将能够从前 20 个字节解析基本 object (并且可能通过存储在索引文件或其他东西中的偏移量在包文件中找到它)。

是的; 或者,如果这是一个OBJ_REF_DELTA ,则会在此处存储一个负的相对 position。

对于任何普通的包文件, OBJ_OFS_DELTA object 必须在包文件中。 包文件可能不引用本身不存在的对象。 然而,精简包违反了此规则,并且OBJ_OFS_DELTA可以引用不在包中的 object,在这种情况下,您必须在其他一些包文件中找到 object 或松散的 ZA8CFDE6331BD59EB2AC966F8。

(多包索引文件,如果存在,为您提供另一种方法来查找包含某些对象的包文件。)

然后是 delta 的 zlib 压缩数据。 解压后的数据是什么样子的。 这些是复制片段还是插入片段,或两者兼而有之?

两者当然:

它说:

增量以源长度和目标长度开始,都编码为可变长度整数,这对于错误检查很有用,但不是必需的。 在此之后,有一系列指令,可能是“复制”(MSB = 1)或“插入”(MSB = 0)。

通过增量开始,它们是否意味着基础 object 的 ref 之后的压缩数据? 不,因为他们说复制指令用于从基础 object 复制...

正确的。 我们有这些不必要的错误检查值,如果我们愿意,我们可以完全忽略它们。 然后我们有说明,内容为:

  • 从增量基础 object 在增量基础 object 的偏移量 O 处复制 N 个字节

(其中有两个可变长度的数字),或者:

  • 插入 N 个字节

(其中有一个可变长度的数字)。 这些数字被巧妙地编码以节省空间,但忽略巧妙之处,让我们假设我们有一个 N 和一个 O(用于复制)或 N(用于插入):

为什么没有删除选项?

你什么时候用一个? 假设我们想在偏移量 100 处获取前 10 个字节,然后在偏移量 6 处获取接下来的 32 个字节。结果是 42 个字节长。 您想删除这 42 个字节中的哪一个? 为什么? 为什么我们不只占用 9 个字节或 31 个字节?

你可能会说:好吧,如果我可以取 32 个字节并在中间删除一个字节,我会得到我想要的 31 个字节,但我们可以将其编码为“在偏移量 6 处取 15 个字节,然后在偏移量 22 处取 16 个字节”。 稍长一些,因为我们必须为每个编码一个 N 和 O,而不是一个 N-and-O 和一个 delete-N,但同时它也稍微一些,因为如果我们一个删除,我们需要删除位置的偏移量。 所以最后只是洗了。

我们仍然需要“插入 N 个字节”操作,因为我们可能必须插入在任何现有 object 中都不会出现的inconceivable的字节序列。 缺少这一点,我们需要每个可能的字节至少包含 1 个的对象(一个包含所有 256 个可能字节的单个 object 就足够了)——但这将比我们简单的“插入 N”更有效和更明显。

那么复制和插入指令实际上在哪里呢?

整个 object( OBJ_REF_DELTAOBJ_OFS_DELTA )只包含这些指令 我们将从一些现有的 object 中复制一些块,并在这些复制的部分或全部之前、之间和/或之后插入一些其他块,结果是最终的 object。

...所以也许这意味着我对文件的添加不是增量,而是增量是根据存储为 blob 或其他东西的两个文件计算得出的,并且增量只能具有复制和插入而不能删除. 那是对的吗?

这确实是正确的。 Git starts with "loose-equivalent objects", at least conceptually, and compresses object O k against object O j with each object considered as a single total byte sequence. 压缩器尝试对尽可能多的候选对象O 0O 1O 2 ,...,因为它觉得值得尝试; 获得“最佳”结果的就是最终结果。 请注意, O k现在位于可以用作下一个 object O l的基础对象的事物的“窗口”中,依此类推; 无论Ok是否最终被压缩,这都是正确的。

(有一个最大链长度,所以在某些时候,对象本身必须从必须从必须从必须构建的对象构建的对象构建,等等,不再 go 到 window 中。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM