如果对象已经被压缩,为什么 git pack-objects 会"Compressing objects"?



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

那么为什么git pack-objects(以及所有相关的repackgc命令)有一个非常长的Compressing objects阶段呢?难道不应该只是复制它们吗?

例如:

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

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

更新说明:

  • 我已经设置了设置和选项,这样就不会有效地进行delta压缩。增量压缩对于存储2 TB的.NEF图像没有用处

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

确实如此。但是它们被压缩了。

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

不管怎样,这些命令--git pack-objectsgit repackgit gc只是为您运行git repack——将许多对象组合到一个包文件中。

包文件是压缩对象的一种不同的方式。松散对象是独立的:Git只需要读取松散对象并对其运行zlib膨胀传递,就可以获得该对象的未压缩数据。相比之下,包文件包含许多对象,其中一些对许多对象首先是增量压缩

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

传统上,这使用的观察结果是,某些文件(如foo.ccfoo.py)往往会随着时间的推移而变化,在文件中的某个地方添加和/或删除几行,但大部分内容保持不变。如果我们可以说:获取所有以前的版本,但随后添加和/或删除这些行,那么我们可以在比存储其中一个版本所需的空间小得多的空间中存储这两个版本。

当然,我们可以在以前的delta压缩文件的基础上构建一个delta压缩的文件:获取扩展以前的del塔压缩文件的结果,并应用这些delta这些使delta链,它可以是你喜欢的长度,也许可以一直追溯到文件最初创建的点。

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

但是,Git不会将文件存储为文件。您已经知道,文件数据存储为blob对象,该对象最初只是zlib放气,其他方面则完好无损。给定一个对象集合,其中一些是文件数据,另一些不是(提交、树或带注释的标记对象),则根本不清楚哪些数据属于哪个文件。因此,Git所做的是找到一个可能的候选者:一些看起来与其他对象非常相似的对象可能最好通过说从另一个对象开始,然后进行这些delta更改来表达

CPU在压缩上花费的大部分时间都在寻找好的链。如果版本控制系统对文件(或对象)的选择不好,则压缩效果不会很好。Git使用了一系列启发式方法,包括窥探树对象来重建文件名(仅限基本名称,而非完整路径名称),因为否则时间复杂性会变得非常疯狂。但即使使用启发式方法,找到好的delta链也是昂贵的。通过"窗口"one_answers"深度"设置,可以调整到底有多贵。

有关包文件的更多信息,请参阅Git中的Documentation/technology目录。

注意:关于git pack-objects--depth自变量,这是由torek在"如何减少现有git克隆的深度"作为:

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

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

选择";CCD_ 15">(man)取CCD_ 16和CCD_;输入验证已经收紧。

请参阅Jeff King(peff)的提交6d52b6a、提交49ac1d3、提交953aa54、提交9535678、提交5489899(2021年5月1日)
(由Junio C Hamano合并——gitster——于2021年5月11日提交第1af57f5号文件)

pack-objects:将负深度箝位为0

签字人:Jeff King

负的delta深度没有意义,并且代码没有准备好处理它。
如果通过"CCD_ 21";在命令行上,然后从break_delta_chains():

cur->depth = (total_depth--) % (depth + 1);

触发除以零
根据C标准,这是未定义的行为,但在POSIX系统上会导致SIGFPE终止进程
这当然是通知用户命令无效的一种方式,但将其视为"更友好一些;不允许任何delta";,这是我们已经为CCD_ 23所做的。

相关内容

最新更新