git pack文件需先校验12字节头部(pack魔数、版本2、对象总数),再按变长header逐对象解压,delta对象须依赖.idx文件定位base,缺失.idx只能低效顺序扫描。

Git 的 pack 文件不是单个对象的简单拼接,而是经过 delta 压缩、对象去重、索引协同的一整套二进制打包格式。直接用 zlib 解压原始内容会失败——因为 pack 文件头部有固定结构,对象数据是 delta 编码的,且需配合 .idx 文件才能随机访问。
pack 文件开头 12 字节必须校验
每个合法 pack 文件以 4 字节魔数 PACK(ASCII)开头,紧随其后是 4 字节版本号(目前只支持 0x00000002),再后是 4 字节对象总数(网络字节序)。漏读或误判这 12 字节,后续所有解析都会偏移错位。
- 用
std::ifstream以std::ios::binary模式打开,read()前先seekg(0) - 版本号不为 2 时应拒绝解析,Git 官方未定义 v3 行为
- 对象总数字段需用
ntohl()转为主机序,否则在 ARM 或大端机器上会读成 0
对象条目(object entry)不是固定长度
pack 文件中每个对象以变长 header 开始:1 字节类型 + 可变长 size 字段(7-bit 编码)。header 后才是压缩数据(zlib deflate stream),但该数据可能是 base 对象(OBJ_COMMIT/OBJ_TREE/OBJ_BLOB)或 delta(OBJ_OFS_DELTA/OBJ_REF_DELTA)。
-
OBJ_OFS_DELTA的 delta base 由 header 后紧跟的偏移量(variable-length integer)指定,需向前回溯计算位置 -
OBJ_REF_DELTA的 base 是另一个对象的 SHA-1,必须查.idx文件获取其在 pack 中的偏移 - 不能对整个 pack 数据流调用一次
inflate();必须按对象边界逐个解压,且对 delta 类型还需先还原 base
没有 .idx 文件就无法安全随机访问
pack 文件本身不包含对象 SHA-1 到偏移的映射。Git 运行时依赖同名 .idx 文件(如 pack-abc123.idx)提供二分查找能力。若缺失 idx,你只能顺序扫描 pack 文件并计算每个对象的 SHA-1,效率极低且无法跳过无效区域。
-
.idxv2 格式含 256 个 fanout 表项(累计计数),接着是 SHA-1 排序列表和 32 位偏移数组 - 必须用
sha1哈希值做二分查找,而非字符串比较——因为 idx 中 SHA-1 是紧凑的 20 字节二进制序列 - 某些旧工具生成的 v1 idx 已淘汰,解析时需检查 idx 头部魔数
\377tOc并跳过 8 字节校验和
真正难的不是解压,而是理解 delta 链如何展开、fanout 表怎么定位区间、以及何时该用 offset delta 而非 ref delta 还原对象。这些逻辑一旦写错,解出来的 commit 就会 missing tree 或 parent,tree 里 blob SHA-1 也会错位——而这种错误不会报 zlib error,只会静默产出垃圾数据。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











