跳转至

Packfile

当 Git 仓库对象很少时,使用 loose object 很直观。
每个对象就是对象库里一个单独压缩文件,容易理解,也容易调试。

但对象一多,问题就来了:

  • 文件太碎;
  • 文件系统负担变重;
  • 网络传输不高效;
  • 很多对象内容相似,却没有一起压缩。

这时就需要 packfile

为什么需要 packfile

packfile 的目标主要有两个:

  1. 降低存储碎片和空间浪费
  2. 提高传输效率

Git 在本地做 gc、在远端做 fetch / push 时,都离不开 pack 的思路。

.pack 文件里是什么

一个 .pack 文件本质上是多个对象的二进制打包结果。
它通常包含:

  • 文件头;
  • 对象数量;
  • 一系列对象实体;
  • 可能的 delta 对象;
  • 最终校验信息。

这样对象就不再是一个目录里无数零散小文件,而是被组织成一个更紧凑的二进制包。

为什么还需要 .idx

如果只有 .pack,想找某个对象时,你可能得把整包从头扫到尾。
这显然不高效。

所以 Git 还会配套一个 .idx 索引文件。它大致负责:

  • 记录对象 ID 的有序列表;
  • 提供 fan-out table;
  • 提供对象偏移量;
  • 让程序能更快地定位对象在 .pack 中的位置。

简单理解就是:

  • .pack 负责“装”
  • .idx 负责“找”

delta 对象为什么重要

很多对象之间其实非常像。
比如同一个大文本文件修改了几行,前后两个版本大部分内容都一样。

如果每次都完整存一份,会浪费很多空间。
因此 pack 里常会使用 delta 思路:

  • 记录“基对象是什么”;
  • 记录“在这个基对象基础上如何变成目标对象”。

这样传输和存储都能明显更省。

pack 和远端同步的关系

一旦谈到 clonefetchpush,packfile 几乎就绕不过去。
因为远端同步的本质并不是“逐文件复制工作区”,而是:

  • 找出缺失对象;
  • 把这些对象组织成可传输的包;
  • 对方接收后写入对象库并更新 refs。

所以 pack 是 Git 分布式能力的重要基础设施。

python-git-reproduction 中的意义

这个项目已经实现了:

  • pack v2 基础读取;
  • idx v2 基础读取;
  • 包内对象随机寻址;
  • ref-delta 解析;
  • 非 delta pack 生成;
  • 本地路径远端和 .pygit 服务端同步。

也就是说,这个项目已经不是只会玩 loose object 的小练习了,而是开始触及 Git 分布式同步的真正骨架。