Git打包文件

原文: 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, 等等).

时间: 2024-11-07 22:16:05

Git打包文件的相关文章

eclipse设置git忽略文件

使用eclipse开发的程序员们经常会接触版本控制软件,这里只要说下eclipse使用egit的情况下设置忽略文件. 特此说明在这里使用window->team->ignored对于git来说是不起效果的,它对svn有效果,好了不说废话了. 直接选择:windows->show view->Navigator 直接在最左侧选择要忽略的文件->右键->team->ignore 保存即可 常用git忽略文件: /bin//.project/.gitignore/.cl

android studio开发工具的android library打包文件(.aar)本地引用

by 蔡建良 2014-5-13 关键点: 利用Gradle发布本地maven库支持android library 打包文件(*.aar) 的本地引用 开发环境: windows7 64位操作系统 android studio0.5.8 (1) 安装maven1.在安装maven之前,先确保已经安装JDK1.6及以上版本,并且配置好环境变量.2.下载maven3,最新版本是Maven3.2.1 ,下载地址:http://maven.apache.org/download.html 下载apach

【转】C#打包文件夹成zip格式

原文地址 C#打包文件夹成zip格式(包括文件夹和子文件夹下的所有文件)C#打包zip文件可以调用现成的第三方dll,事半功倍,而且该dll完全免费,下载地址:SharpZipLib下载完解压缩后,把 ICSharpCode.SharpZipLib.dll 拷贝到当前项目的目录下(如果偷懒的话,可以直接拷贝到当前项目的bin\Debug目录下),在VS打开的项目引用上右键添加引用 ICSharpCode.SharpZipLib.dll然后,在VS打开的项目上右键新建一个类,命名为 ZipHelp

对git中文件各个状态的理解

我之前开发java项目的时候也有用过版本管理工具svn,不过老是弄不清楚各个状态之间的关系和操作的含义,最近使用github管理自己的代码和一些笔记,对于一些操作还是不太理解(太笨了...),网上也查过一些零零碎碎的相关内容,不过还是模糊不清.于是我打算较为系统地学习一下git和github.http://git-scm.com/book/zh/v1这个网站系统地介绍了git原理还有操作等等,有兴趣的朋友可以参考学习. 要使用git工具进行版本管理,首先要明白git各种状态的含义.如下图所示,

git忽略文件【转】

转自: http://cwind.iteye.com/blog/1666646 有很多文件不必使用git管理.例如Eclipse或其他IDE生成的项目文件,编译生成的各种目标或临时文件等.使用git status时,会在Untracked files里面看到这些文件列表,在一次需要添加的文件比较多时(使用git add . / git add -u),会把这些所有的未跟踪文件添加进索引. ============一些牢骚============ 于是自然想要告诉git把这些文件忽略,我们当然会想

Git过滤文件和文夹

Git过滤文件和文夹 第一步:添加".gitignore"文件 往项目根目录添加一个文件".gitignore".这文件和".git"文件夹同级. 但是在windows下无法创建".gitignore"文件名,必须把文件名改成这样".gitignore.", 在文件名最后加一个英文句号就可以了. 第二步:设置过滤条件 bin/ 过滤所有bin文件夹 obj/ 过滤所有obj文件夹 ValorNAV_depl

文件打包代码更新 使用json记录打包文件信息

经过之前的几次试验 决定使用json记录打包文件信息 #include "Package.h" #include "json/json.h" #include <string> #include <iostream> /************************************************************** 技术博客 http://www.cnblogs.com/itdef/   技术交流群 群号码:324

java后台生成zip打包文件

/** * * @param zipFile 压缩包文件对象 * @param listKey 压缩的图片物理地址 * @return */ public static boolean packageZip(File zipFile,List<String> listKey){ //图片打包操作 ZipOutputStream zipStream = null; FileInputStream zipSource = null; BufferedInputStream bufferStream

git关于文件权限修改引起的冲突及忽略文件权限的办法

我们在使用git进行版本管理的时候,有时候只是修改了文件的权限,比如将pack.php修改为777,但其实文件内容并没有改变,但是git会认为此文件做了修改,原因是git把文件权限也算作文件差异的一部分了.下面做个测试: 1.修改版本库的文件的权限,然后使用diff查看下改变. 可以看到git把文件权限也列入了版本管理. 2.在另外一个地方clone这个版本库,修改pack.php文件,然后提交. 3.在原版本库下面更新内容. $ git pull 可以看到提示冲突. 解决办法: git中可以加