土法炼钢兴趣小组的算法知识备份

【Git 内部】pack-objects 与 delta 压缩

文章导航

分类入口
opensource
标签入口
#git#git-internals#pack-objects#delta#REF_DELTA#OFS_DELTA

目录

pack 的价值不只是「少文件」——对相似内容,Git 存 delta(相对基对象的二进制 diff),大幅缩小 pack 体积。git pack-objectsgit repack / git gc 内部调用)在窗口内挑对象建 delta 链。理解链式结构,才能读懂 git verify-pack 里的 chain lengthREF_DELTA 行。

本文从格式视角说明 delta 类型与实测现象;不拆 git/gitdiff-delta.c 的实现细节。pack 字节布局见 第 07 篇


一、为何需要 delta

松散 blob 按完整内容寻址去重——同一字节序列只存一份。但近似内容(只改几个字符的 20 个文件)会产生 20 个几乎不同的 SHA,无法去重。pack 阶段在同一 pack 内选基对象,存「补丁」而非全文。

两类 delta(gitformat-pack):

pack 内 OFS_DELTA 与 REF_DELTA 两种基对象引用方式

二、实测:20 个相似文件

构造仓库:20 个结构相同的文本文件,先提交,再全部改一字提交第二次,git repack -ad

git verify-pack -v .git/objects/pack/*.pack | tail -5

输出片段:

6fb7127d7c0e0eba2c781114f513d21e0c580fcc commit 65 77 193 1 a5f7463aa0e4a38ee4bc052c58b85c6d52285b00
…
non delta: 43 objects
chain length = 1: 1 object

第二行 commit 末尾的 1 a5f7463… 表示 REF_DELTA,基对象为前一 commit。大量 blob 仍为 non delta(短文本、互不相同),但已出现至少一条 delta 链。pack 总大小约 16K(du -sh .git/objects/),相对 43 个松散对象仍更紧凑。

窗口与启发式由 pack.windowpack.depth 等配置影响;具体压缩率随内容分布变化,本文不给出未对照基线的倍率结论。

repack 前后松散文件数与 pack 体积(临时仓库实测)

三、thin pack

thin pack 在传输时使用:接收方已有基对象,发送方 pack 内 REF_DELTA 指向接收方库中已有 SHA,pack 内可不包含基对象全文。git index-pack 在入库时可能需 fix-thin 补全。这与 fetch/push 落盘 直接相关。


四、delta 链长度

git verify-pack 统计:

chain length = 1: 1 object

表示有 1 个对象的 delta 链长度为 1(一层 delta)。链过长会增加读取成本(需逐级应用 delta),pack.depth 限制建链深度以权衡空间与 CPU。


五、与 gc 的配合

git gc 调用 repack 重建 pack、丢弃冗余松散对象(第 10 篇)。历史越长、相邻版本越相似,delta 收益越明显——与版本控制系统存储模型一致。


六、本文边界

复现脚本思路:循环创建 f1.txtf20.txt,两次提交后 git repack -ad && git verify-pack -v .git/objects/pack/*.pack


参考资料

系列索引Git 内部结构 · 上篇pack/idx 格式 · 下篇commit-graph 与 bitmap

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .