Git使用增量压缩来存储彼此相似的对象。
此算法是否已标准化并在其他工具中使用?是否有描述格式的文档?它与xdelta / VCDIFF / RFC 3284兼容吗?
答案 0 :(得分:64)
我认为用于pack files的差异算法与其中一个delta encoding相关联:initially (2005) xdelta,然后是libXDiff。
但是,如下所述,它转移到自定义实现。
无论如何,mentioned here:
Git在packfiles中仅对进行了。< 但是当你通过SSH推送时,git会生成一个包含文件,而另一方则不会提交 有,并且这些包是薄包装,因此它们也有增量...但是远程端然后为这些薄包装添加基础使它们独立。
(注意:创建许多packfiles,或者在巨大的packfile中检索信息代价高昂,并解释为什么git无法处理好的大文件或巨大的回购。
详情请见“git with large files”)
This thread也提醒我们:
实际上,我记得并理解, LibXDiff,而不是xdelta ,最初是因为网络带宽(这比磁盘空间要贵得多)使用单个mmapped文件而不是大量松散对象的 I / O性能。
此2008 thread中提到了LibXDiff。
然而,从那时起,算法已经发展,可能是自定义的,2011 thread illustrates,diff-delta.c
的标题指出:
因此,严格来说,Git中的当前代码根本不与libxdiff代码有任何相似之处。
然而,两种实现背后的基本算法是相同的 研究libxdiff版本可能更容易,以便了解它是如何工作的。
/*
* diff-delta.c: generate a delta between two buffers
*
* This code was greatly inspired by parts of LibXDiff from Davide Libenzi
* http://www.xmailserver.org/xdiff-lib.html
*
* Rewritten for GIT by Nicolas Pitre <nico@fluxnic.net>, (C) 2005-2007
*/
有关packfiles the Git Book的更多信息:
documentation section,现在(2018年第二季度)声明:
对象类型
有效的对象类型是:
OBJ_COMMIT
(1)OBJ_TREE
(2)OBJ_BLOB
(3)OBJ_TAG
(4)OBJ_OFS_DELTA
(6)OBJ_REF_DELTA
(7)类型5保留用于将来扩展。类型0无效。
Deltified representation
从概念上讲,只有四种对象类型:commit,tree,tag和 斑点。
但是为了节省空间,可以将对象存储为“delta” 另一个“基础”对象。
这些表示被分配了新类型的delta和ref-delta,它们仅在包文件中有效。
ofs-delta
和ref-delta
都存储要应用的“delta” 另一个对象(称为“基础对象”)来重建对象 他们之间的区别是,
- ref-delta直接编码20字节的基础对象名称。
- 如果基础对象位于同一个包中,则ofs-delta会对包中基础对象的偏移量进行编码。
如果基础对象在同一个包中,也可以进行分类 Ref-delta也可以指包外的一个对象(即 所谓的“薄包”)。然而,当存储在磁盘上时,包应该 是自包含的,以避免循环依赖。
增量数据是重建对象的一系列指令 来自基础对象。
如果基础对象已经过分层,则必须首先将其转换为规范形式。每条指令都会向目标对象附加越来越多的数据,直到完成为止 到目前为止,有两条支持的说明:
- 一个用于复制源对象和
的字节范围- 用于插入嵌入指令本身的新数据。
每条指令都有可变长度。指令类型已确定 在第一个八位字节的第七位。以下图表如下 RFC 1951中的约定(Deflate压缩数据格式)。
答案 1 :(得分:22)
Git delta编码是基于复制/插入的。
这意味着派生文件被编码为可以表示副本的操作码序列 指令(例如:从基本文件复制y字节从偏移x开始到目标缓冲区)或 插入指令(例如:将下一个x字节插入目标缓冲区)。
作为一个非常简单的例子(取自文件'Delta Compression的文件系统支持'),考虑我们要创建一个delta缓冲区来将文本“代理缓存”转换为 “缓存代理”。 结果说明应为:
转换为git的编码变为:
(字节1-3代表第一条指令)
(字节4-6代表第二条指令)
(字节7-8表示最后一条指令)
请注意,在最后一条复制指令中没有指定偏移量,这意味着偏移量为0.其他位 当需要更大的偏移/长度时,也可以设置复制操作码。
结果delta缓冲区在这个例子中有8个字节,这不是一个压缩 因为目标缓冲区有12个字节,但是当这个编码应用于大文本文件时它可以 发挥巨大作用。
我最近将node.js library推送到了github 它使用git delta编码实现diff / patch函数。该 code应该更具可读性 并且比git源中的那个进行了评论,这是经过大量优化的。
我也写过一些 tests解释 每个示例中使用的输出操作码的格式与上述类似。
答案 2 :(得分:4)
此算法是否已标准化并在其他工具中使用?
包格式是公共API的一部分:用于推送和提取操作的传输协议使用它来通过网络发送更少的数据。
除了引用之外,它们至少在其他两个主要的Git实现中实现:JGit和libgit2。
因此,不太可能对格式进行向后不兼容的更改,并且可以认为是标准化的&#34;从那个意义上说。
来自文档的这个惊人的文件描述了包算法中使用的启发式方法作为Linus的电子邮件的有趣评论:https://github.com/git/git/blob/v2.9.1/Documentation/technical/pack-heuristics.txt