原文: http://gitbook.liuhui998.com/7_5.html

一、打包文件索引
首先, 我们来看一下打包文件索引, 基本上它只是一系列指向打包文件内位置的书签.
打包文件索引有两个版本.
 版本1的格式用于Git 1.6版本之前, 版本2的格式用于Git 1.6及以后的版本. 
但是版本2可以被Git 1.5.2及以上的Git读取, 同时也被后向移植(backport)到了1.4.4.5版本.
版本2包含了每个对象的CRC校验值, 因此在重打包的过程中, 压缩过的对象可以直接进行包间拷贝(from pack to pack)而不用担心数据损坏. 版本2的打包文件索引同时亦支持大于4G的打包文件.
在两个版本格式中, sha1表存储的是对象的SHA1值,并把它们按照其SHA1值进行排序(以便于对这个表进行二分搜索),  offset表存储的是sha1表中对应位置的对象在打包文件中的偏移值。
为了加速对象的查找,git使用了分段的思想,在打包文件中包含了一个fanout表。fanout表用一种特殊的方法指向offset/sha1表。
简单的说应该是这样的,fanout[0]表示的是SHA1值以0x00开头的所有的对象中SHA1值最小的对象在offset/sha1表中的偏移;fanout[1]表示的是SHA1值以0x01开头的所有的对象中SHA1值最小的对象在offset/sha1表中的偏移;fanout[2]表示的是SHA1值以0x02开头的所有的对象中SHA1值最小的对象在offset/sha1表中的偏移。以此类推,fanout[254]表示的是SHA1值以0xfe开头的所有的对象中SHA1值最小的对象在offset/sha1表中的偏移,fanout[255]表示的是SHA1值以0xff开头的所有的对象中SHA1值最大的对象在offset/sha1表中的偏移,它同时也表示了当前offset/sha1表的大小。
因此通过SHA1值查找一个对象时,首先通过SHA1值的前两位在fanout表中,确定它在offset/sha1表的一个区间范围,然后再在sha1表中根据SHA1值使用二分法进行查找。这样通过fanout表对于最坏的情况就减少了8次二分搜索迭代。
 
在第1版中, offset(偏移)和SHA值存在在同一位置. 但是在第2版中, SHA值, CRC值和offset被放在不同的表中. 两个版本的文件最后都是索引文件以及指向的打包文件的CRC校验值.
 
很重要的一点是, 要从打包文件中提取(extract)出一个对象, 索引文件不是必不可少的. 索引文件的作用是帮助用户快速地从打包文件中提取对象. 那些"上传打包"(upload-pack)和"取回打包"(receive-pack)程序(译注: 实现push和fetch协议的程序)使用打包文件格式(packfile format)去传输对象, 但是没有使用索引 .因为 索引可以在上传或者取回打包文件之后通过扫描打包文件重新建立.
二、打包文件格式
打包文件格式是很简单的. 它有一个头部(header)和一系列打包过的对象(每个都有自己的header和body), 还有一个校验尾部(trailer). 前4个字节是字符串'PACK', 它用于确保你找到了打包文件的起始位置. 紧接着是4个字节的打包文件版本号, 之后的4个字节指出了此文件中入口(entry)的个数. 你可以用下面Ruby程序读出打包文件的头部:
def read_pack_header
  sig = @session.recv(4)
  ver = @session.recv(4).unpack("N")[0]
  entries = @session.recv(4).unpack("N")[0]
  [sig, ver, entries]
end
头部之后是一系列按照SHA值排序的打包对象, 每一个打包对象包含了头部和内容. 打包文件的尾部是该文件中所有(已排序)SHA值的SHA1校验值(20字节长)(译注: 即按照排序好的顺序进行迭代SHA1运算).

对象头部(object header)由1个或以上的字节按序组成, 它指出了后面所跟数据的类型及展开后的尺寸. 头部的每一个字节有7位用于数据, 第1位用于说明头部是否还有后续字节. 如果第1位是'1', 你需要再读入1个字节(译注: 即下一字节仍属于头部), 否则下一字节就是数据. 第一个字节的前3位指定了数据的类型, 具体含义参见下表.

 
(3个位可以组合成为8个数. 在当前的使用中, 0(000)是'未定义', 5(101)目前未被使用.)
 
这里我们举一个由两个字节组成的头部的例子. 第1个字节的前3位说明了数据的类型是提交(commit), 余下的4位和第2个字节的7位组成的数字是144, 说明数据展开后的长度是144字节.
 
值得注意的一点是, 对象头部中包含的'尺寸'不是后面跟着的数据的长度, 而是数据展开之后的长度. 因此, 打包索引文件中的偏移是很有用的, 有了它你不必展开每一个对象就可以得到下一个头部的起始位置.
对于非delta对象, 数据部分就只是zlib压缩后的数据流. 对于那两种delta对象, 数据部分包含了它所依赖的基对象(base object)以及用于重构对象的delta(差异)数据. 数据的前20个字节称为ref-delta, 它是基对象SHA值的前20个字节. ofs-delta存储了基对象在同一打包文件中的偏移. 任何情况下, 有两个约束必须严格遵守:
1、delta对象和基对象必须位于同一打包文件;
2、delta对象和基对象的类型必须一致(即tree对tree, blob对blob, 等等).

Git打包文件的更多相关文章

  1. dotnet pack 打包文件版本号引起 "Could not load file or assembly" 问题

    如果不是遇到,真的不会想到,代码世界的问题真是千奇百怪,这次遇到的是 dotnet pack 打包文件版本号引起的问题. 之前进行 nuget 打包都是在 Visual Studio build 时进 ...

  2. gulp批量打包文件并提取公共文件

    gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器. browseriyf是模块化打包工具. 一般情况下,Browserify 会把所有的模块打包成单个文件.单个文件在大多数情况下是 ...

  3. java打包文件夹为zip文件

    //待压缩的文件目录 String sourceFile=sourceFilePath+"\\"+userName; //存放压缩文件的目录 String zipFilePath ...

  4. Wix 安装部署(一)同MSBuild 自动生成打包文件

    因为项目需要,最近在研究Wix打包部署,园子里也有一些关于wix的博客,方方面面,讲的点各不同.我自己也在测试过程中,写下过程,以供参考.最新版本WiX Toolset v3.7,如何安装的就不说了, ...

  5. JAVA代码实现下载单个文件,和下载打包文件

    //下载单个文件调用方法 /**     * response     * imgPath 下载图片地址    * fileName 保存下载文件名称    * @date 2015年4月14日 下午 ...

  6. java jar包解析:打包文件,引入文件

    java jar包解析:打包文件,引入文件 cmd下: jar命令:package包打包 javac命令:普通类文件打包 Hello.java: package org.lxh.demo; publi ...

  7. git 添加文件

    git 添加文件三步骤 git add filename git commit -m 'remarks' git push origin master

  8. 请问用Inno_Setup打包文件夹时怎么排除其中一个文件?

    请问用Inno_Setup打包文件夹时怎么排除其中一个文件? 该文件夹下有几十个文件,多个文件夹,我要一个个加进去该累死,也容易出问题.不知道能不能实现我要的目的. http://www.jrsoft ...

  9. Git忽略文件方法【转】

    转自:http://www.cnblogs.com/shangdawei/archive/2012/09/08/2676669.html http://cwind.iteye.com/blog/166 ...

随机推荐

  1. Redis学习——SDS字符串源码分析

    0. 前言 这里对Redis底层字符串的实现分析,但是看完其实现还没有完整的一个概念,即不太清楚作者为什么要这样子设计,只能窥知一点,需要看完redis如何使用再回头来体会,有不足之处还望告知. 涉及 ...

  2. xheditor编辑器的使用

    xheditor编辑器的使用 一个博客.cms网站都一定会用到一个html编辑器,刚好xmfdsh在做网站时候需要用到这类编辑器,在对比了之后,发现其实差不了多少,刚好一个不错的friend在用xhe ...

  3. BloomFilter 与 Cuckoo Filter

    BloomFilter 与 CuckooFilter Bloom Filter 原理 Bloom Filter是一种空间效率很高的随机数据结构,它的原理是,当一个元素被加入集合时,通过K个相互独立的H ...

  4. Nginx重新编译添加模块

    原文链接:http://www.linuxidc.com/Linux/2013-06/86438.htm 找到安装nginx的源码根目录,如果没有的话下载新的源码 http://nginx.org t ...

  5. 注册Com组件..

    开发一些第三方的接口或者功能时..有时会需要接入对方提供Com组件..是一个dll文件.. 这个文件会在你的程序中引用.. 比如一个CMBChina.dll文件..这是招商银行的支付开发时必备的.. ...

  6. 缺陷跟踪系统Mantis Bug Tracker

    缺陷管理平台Mantis,也做MantisBT,全称Mantis Bug Tracker. 项目在github的地址:https://github.com/mantisbt/mantisbt Mant ...

  7. Spring Quartz定时调度任务配置

    applicationContext-quartz.xml定时调度任务启动代码: <?xml version="1.0" encoding="UTF-8" ...

  8. 一道Twitter面试题

    在微博上看到的这个问题,忍住没看答案自己解决了.建议没看过的同学也自己先尝试下. “看下面这个图片” 在这个图片里我们有不同高度的墙.这个图片由一个整数数组所代表,数组中每个数是墙的高度.上边的图可以 ...

  9. STAR-H1208M集线器不支持同时挂载多个nfs

    今天在两个触摸屏上都加入了开机加载nfs的操作. 没想到会出现以下错误: pmap_getmaps.c: rpc problem: RPC: Unable to receive; errno = Co ...

  10. Codeforces 675C Money Transfers 思维题

    原题:http://codeforces.com/contest/675/problem/C 让我们用数组a保存每个银行的余额,因为所有余额的和加起来一定为0,所以我们能把整个数组a划分为几个区间,每 ...