git二进制差异算法(增量存储)是否标准化?

时间:2012-02-28 07:30:32

标签: git compression binary-diff vcdiff

Git使用增量压缩来存储彼此相似的对象。

此算法是否已标准化并在其他工具中使用?是否有描述格式的文档?它与xdelta / VCDIFF / RFC 3284兼容吗?

3 个答案:

答案 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 illustratesdiff-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的更多信息:

packfile format


Git 2.18 adds to the delta description中的

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-deltaref-delta都存储要应用的“delta”   另一个对象(称为“基础对象”)来重建对象   他们之间的区别是,

     
      
  • ref-delta直接编码20字节的基础对象名称。      
        
    • 如果基础对象位于同一个包中,则ofs-delta会对包中基础对象的偏移量进行编码。
    •   
  •   
     

如果基础对象在同一个包中,也可以进行分类    Ref-delta也可以指包外的一个对象(即   所谓的“薄包”)。然而,当存储在磁盘上时,包应该   是自包含的,以避免循环依赖。

     

增量数据是重建对象的一系列指令   来自基础对象。
  如果基础对象已经过分层,则必须首先将其转换为规范形式。每条指令都会向目标对象附加越来越多的数据,直到完成为止   到目前为止,有两条支持的说明:

     
      
  • 一个用于复制源对象和
  • 的字节范围   
  • 用于插入嵌入指令本身的新数据。
  •   
     

每条指令都有可变长度。指令类型已确定   在第一个八位字节的第七位。以下图表如下   RFC 1951中的约定(Deflate压缩数据格式)。

答案 1 :(得分:22)

Git delta编码是基于复制/插入的。

这意味着派生文件被编码为可以表示副本的操作码序列 指令(例如:从基本文件复制y字节从偏移x开始到目标缓冲区)或 插入指令(例如:将下一个x字节插入目标缓冲区)。

作为一个非常简单的例子(取自文件'Delta Compression的文件系统支持'),考虑我们要创建一个delta缓冲区来将文本“代理缓存”转换为 “缓存代理”。 结果说明应为:

  1. 从偏移7复制5个字节(从基础缓冲区复制'缓存')
  2. 插入两个空格
  3. 从偏移0复制5个字节(从基础缓冲区复制'代理')
  4. 转换为git的编码变为:

    (字节1-3代表第一条指令)

    • 0x91(10010001),分为
      • 0x80(10000000)(最高有效位设置使其成为'从基本到输出的复制'指令)
      • 0x01(00000001)(表示'前进一个字节并将其用作基本偏移量)
      • 0x10(00010000)(提前一个字节并将其用作长度)
    • 0x07(偏移)
    • 0x05(长​​度)

    (字节4-6代表第二条指令)

    • 0x02(由于未设置MSB,这意味着'将下两个字节插入输出')
    • 0x20(空格)
    • 0x20(空格)

    (字节7-8表示最后一条指令)

    • 0x90(10010000),分为
      • 0x80(10000000)(表示'复制')
      • 0x10(00010000)(提前一个字节并将其用作长度)
    • 0x05(长​​度)

    请注意,在最后一条复制指令中没有指定偏移量,这意味着偏移量为0.其他位 当需要更大的偏移/长度时,也可以设置复制操作码。

    结果delta缓冲区在这个例子中有8个字节,这不是一个压缩 因为目标缓冲区有12个字节,但是当这个编码应用于大文本文件时它可以 发挥巨大作用。

    我最近将node.js library推送到了github 它使用git delta编码实现diff / patch函数。该 code应该更具可读性 并且比git源中的那个进行了评论,这是经过大量优化的。

    我也写过一些 tests解释 每个示例中使用的输出操作码的格式与上述类似。

答案 2 :(得分:4)

  

此算法是否已标准化并在其他工具中使用?

包格式是公共API的一部分:用于推送和提取操作的传输协议使用它来通过网络发送更少的数据。

除了引用之外,它们至少在其他两个主要的Git实现中实现:JGitlibgit2

因此,不太可能对格式进行向后不兼容的更改,并且可以认为是标准化的&#34;从那个意义上说。

来自文档的这个惊人的文件描述了包算法中使用的启发式方法作为Linus的电子邮件的有趣评论:https://github.com/git/git/blob/v2.9.1/Documentation/technical/pack-heuristics.txt