简介:
Git的pack文件经过精心构造,可以有效地使用磁盘缓存,并为常用命令和读取最近引用的对象提供“不错”的访问模式。
Git的包文件格式相当灵活(见文档/技术/包,format.txt,或将打包文件在Git的社区图书)。打包文件以两种主要方式存储对象:“未删除”(获取原始对象数据并进行压缩压缩)或“删除”(针对某个其他对象形成增量,然后对生成的增量数据进行压缩压缩)。包中存储的对象可以按任何顺序排列(不必(不必)按对象类型,对象名称或任何其他属性来排序),并且可以针对相同类型的任何其他合适的对象制作已删除的对象。
Git的pack-objects命令使用了几种启发式方法,可以为常见命令提供出色的参考位置。这些启发式方法既控制了已删除对象的基础对象的选择,又控制了对象的顺序。每种机制大部分都是独立的,但是它们有一些共同的目标。
Git确实形成了增量压缩对象的长链,但是试探法试图确保只有“旧”对象才在长链的末端。core.deltaBaseCacheLimit
自动使用增量基本缓存(其大小由配置变量控制
),并且可以大大减少需要读取大量对象(例如git log
-p
)的命令所需要的“重建”次数。
增量压缩启发式
典型的Git存储库存储大量对象,因此无法合理地比较所有对象以找到将产生最小增量表示形式的对(和链)。
增量基数选择启发式算法是基于这样的想法,即可以在文件名和大小相似的对象中找到良好的增量基数。每种类型的对象都是单独处理的(即,一种类型的对象永远不会用作另一种类型的对象的增量基础)。
为了选择增量基数,将对象(主要)按照文件名和大小排序。进入此排序列表的窗口用于限制被视为潜在增量基础的对象数量。如果一个“足够好” 1个没有找到在其窗口中的对象之间的对象增量表示,则该对象将不被增量压缩。
窗口的大小由的--window=
选项
git pack-objects
或pack.window
配置变量控制。增量链的最大深度由的--depth=
选项git pack-objects
或pack.depth
配置变量控制。该--aggressive
选项可以git gc
极大地扩大窗口大小和最大深度,以尝试创建较小的打包文件。
文件名排序会将名称相同(或至少类似结尾(例如.c
))的条目的对象聚在一起。大小排序从最大到最小,因此删除数据的增量要优先于添加数据的增量(因为删除增量具有较短的表示形式),因此较早,较大的对象(通常是较新的)倾向于用普通压缩表示。
1
什么才算是“足够好”取决于所讨论对象的大小及其潜在的增量基数以及其产生的增量链的深度。
对象排序启发式
对象以“最近引用”的顺序存储在打包文件中。重建最新历史记录所需的对象放在包装中的较早位置,它们将靠近在一起。这通常适用于OS磁盘缓存。
所有提交对象均按提交日期排序(最新的优先),并存储在一起。此放置和排序优化了遍历历史图并提取基本提交信息(例如git log
)所需的磁盘访问。
从第一个存储的(最近的)提交开始,从树开始存储tree和blob对象。每棵树以深度优先的方式进行处理,存储所有尚未存储的对象。这会将重建最新提交所需的所有树木和斑点都放在一个位置。接下来,将按照排序的提交顺序存储尚未保存但以后提交需要的所有树和Blob。
最终对象排序受增量基本选择的影响很小,因为如果为增量表示选择了一个对象并且尚未存储其基本对象,则其基本对象将立即存储在已修改对象本身之前。这样可以防止由于读取基础对象所需的非线性访问而导致磁盘高速缓存未命中,该基础对象后来将“自然”存储在打包文件中。