浅析Git存储—对象、打包文件及打包文件索引

2018-09-04  本文已影响0人  yangziwen

存储是Git完成其他各种功能的基础,本质上是将系统中的文件按一定格式生成版本快照。对Git的存储机制进行一定程度的学习,可有效加深对Git的理解,帮助我们更高效的使用Git,同时也可作为进一步学习Git底层原理的基础。本文主要涉及Git的对象、打包文件及打包索引等内容。


Git的对象

在Git代码库中,commit、tag、目录(tree)、文件(blob)的内容经过压缩后,最终会被保存为Git对象(object)。

有两种形式的Git对象可用于保存这些压缩后的内容,一种是松散对象(loose object),另一种是打包对象(packed object)

松散对象的格式比较简单,每一个对象都会写入到一个独立的文件中,并以对象的SHA1值作为文件名,存储在GIT_DIR/objects目录中(实际会以SHA1的后38个字符[19字节]作为文件名,保存在以SHA1前两个字符[1字节]命名的子目录中)。松散对象存储的内容为zlib.deflate("${type} ${size}\0${data}"),可通过git cat-file -p ${objectId}命令还原指定对象中存储的内容(即data)。

基于松散对象执行Git操作效率较低,因此可通过git gc命令将松散对象转换为打包对象,并保存到GIT_DIR/objects/pack目录的打包文件中。一个打包文件可保存大量对象信息,相比于松散对象,使用打包对象具有以下优点。


Git的打包文件(packfile)

在代码库中,Git会通过单个打包文件保存大量(也可能是全部)打包对象。打包文件会以形如pack-4eb8b183eb6e64e1c9ccaabe91c96f83ad11a2c5.pack的方式命名,并保存在GIT_DIR/objects/pack目录下。打包文件的内容格式如下图所示。


(注意,上图中的红色区域仅用于描述其他区域所占用的空间大小,并不是文件中真实存在的部分)

打包文件中的内容可分为头部(header)数据区尾部(footer)。接下来对这三部分进行描述。

由以上对数据区的描述可知,我们无法根据数据头中记录的未压缩数据长度得知后面压缩数据的结束位置。同时,我们也无法直接通过打包文件中这种略显复杂的数据组织格式实现对打包对象的快速查找。因此需要进一步基于打包文件构造索引文件,才能实现打包对象的快速检索。


Git的打包文件索引(packfile index)

打包文件索引会以形如pack-4eb8b183eb6e64e1c9ccaabe91c96f83ad11a2c5.idx的方式命名,并保存在GIT_DIR/objects/pack目录下。Git可以通过git index-pack ${packfile}命令为打包文件构造索引文件,因此在任何通讯交互场景下,Git均不需要传递打包索引文件,只需传递打包文件即可。

到目前为止,打包索引文件的内容格式有两个版本,V1格式用于Git1.6版本之前,V2格式用于Git1.6版本之后。V2格式的索引文件中,包含了每个对象的CRC校验值,因此在重新打包的过程中,压缩过的对象可以直接进行包间拷贝而不用担心数据损坏。此外V2格式的索引文件可支持大于4G的打包文件。有鉴于此,这里只对V2版本的打包文件索引做进一步描述。


如上图所示,V2版本的打包文件索引可分为头部、fanout表、对象id区、校验和区、偏移量区(包括整形偏移量区和长整型偏移量区)和尾部,各部分内容具体描述如下


本文阐述了Git对象、打包文件、打包文件索引的相关概念和内部结构,可作为进一步了解Git其他底层原理的基础。

上一篇下一篇

猜你喜欢

热点阅读