为什么git pack对象会这样做;“压缩对象”;如果对象已被压缩?

为什么git pack对象会这样做;“压缩对象”;如果对象已被压缩?,git,Git,据我所知,存储在[bare]git存储库中的松散对象是压缩的 …那么为什么git-pack对象(以及所有相关的repack和gc命令)有一个非常长的压缩对象的阶段呢?它不应该只是复制它们吗 例如: objects/75/f0debd8e421ab3f9cc8b6ab539796ae86b705已被压缩。在包文件中,此文件应在其头文件之后立即按字节复制到spot中,因为包文件格式指定压缩数据将到达该位置。。。既然已经压缩了,为什么还要重新压缩呢 如果它可能试图使用不同的压缩。。。我怎么能告诉它不要

据我所知,存储在[bare]git存储库中的松散对象是压缩的

…那么为什么
git-pack对象(以及所有相关的
repack
gc
命令)有一个非常长的
压缩对象的阶段呢?它不应该只是复制它们吗

例如:

objects/75/f0debd8e421ab3f9cc8b6ab539796ae86b705
已被压缩。在包文件中,此文件应在其头文件之后立即按字节复制到spot中,因为包文件格式指定压缩数据将到达该位置。。。既然已经压缩了,为什么还要重新压缩呢

如果它可能试图使用不同的压缩。。。我怎么能告诉它不要这样做,而是按原样使用文件呢

更新注释:

  • 我已经设置了设置和选项,这样就不会有效地进行增量压缩。增量压缩对于存储2 TB的
    .NEF
    图像无效
据我所知,存储在[bare]git存储库中的松散对象是压缩的

是的。但它们是压缩的

…那么为什么git pack对象(以及所有相关的重新打包和gc命令)有一个非常长的压缩对象阶段呢

这些命令-
git-pack对象
git-repack
gitgc
只需运行
gitrepack
,即可将多个对象合并到一个包文件中

包文件是压缩对象的另一种方式。松散对象是独立的:Git只需读取松散对象并在其上运行zlib充气传递即可获得该对象的未压缩数据。相比之下,包文件包含许多对象,其中一些对象对许多对象进行增量压缩

增量压缩的工作原理是:要产生这个对象,首先要产生另一个对象。然后在此处添加这些字节和/或删除N个字节。重复此添加和/或删除操作,直到完成增量列表。(delta指令本身也可以被zlib压缩。)您可能会认为这是一种差异,事实上,一些非Git版本控制系统确实使用diff,或者它们自己的内部差异引擎来生成它们的delta压缩文件

传统上,它使用这样一种观察方式,即某些文件(例如,
foo.cc
foo.py
)会随着时间的推移而变化,方法是在文件中的某个位置添加和/或删除几行,但保持其大部分不变。如果我们可以说:获取所有以前的版本,然后添加和/或删除这些行,那么我们可以用比存储其中一个版本更少的空间来存储这两个版本

当然,我们可以在先前的增量压缩文件上构建一个增量压缩文件:获取扩展先前增量压缩文件的结果,并应用这些增量。这些生成的增量链可以任意长,可能会一直追溯到文件第一次创建的位置

一些(非Git)系统到此为止:每个文件都存储为对以前版本的更改,或者每次存储文件时,系统都存储最新的文件,并将以前的完整副本(以前是最新的,因此是完整副本)转换为将“最新”转换为“以前”所需的增量。第一种方法称为正向增量存储,而第二种方法当然是反向增量存储。正向增量往往处于非常不利的地位,因为提取文件的最新版本需要提取第一个版本,然后应用非常长的增量序列,这需要很长时间。因此,RCS使用反向增量,这意味着获取最新版本的速度很快;它的版本很旧,速度很慢。(然而,出于技术原因,这只适用于RCS称之为主干的部分。RCS的“分支”使用前向增量。)Mercurial使用前向增量,但偶尔会存储文件的新完整副本,以保持增量链长度较短。其中一个系统,SCCS,使用了一种SCCS调用交错增量的技术,它为提取任何文件提供了线性时间(但更难生成)

然而,Git并不将文件存储为文件。您已经知道,文件数据存储为blob对象,它最初只是zlib deflated,否则是完整的。给定一组对象,其中有些是文件数据,有些不是(是提交、树或带注释的标记对象),根本不清楚哪些数据属于哪个文件。所以Git所做的就是找到一个可能的候选者:一些看起来很像其他对象的对象,最好的表达方式是说从其他对象开始,然后进行这些增量更改

CPU在压缩上花费的大部分时间在于寻找好的链。如果版本控制系统拾取文件(或对象)的效果不佳,则压缩效果将不太好。Git使用了一系列的启发式方法,包括窥视树对象来重建文件名(仅基础名而非完整路径名),因为否则时间复杂性会变得非常疯狂。但即使使用启发式,找到好的三角洲链也是昂贵的。通过“窗口”和“深度”设置,可调整的成本到底有多高

有关随时间经过多次修订的包文件的(更多)详细信息,请参阅。

注意:关于,在“”中描述为:

当Git对存储在每个包文件中的Git对象使用其修改后的xdelta压缩时,增量链的最大长度。
这与提交DAG的特定部分的深度无关(根据每个分支头计算)

因此,Git 2.32(2021年第2季度)更清晰:

“()的选项采用的数值如
--window
--depth
不应接受负数
cur->depth = (total_depth--) % (depth + 1);