git技术实现分析

来源:互联网 发布:mac mini 发布 编辑:程序博客网 时间:2024/06/05 14:57

 Git 是一套内容寻址文件系统。从内部实现来看,Git 是简单的 key-value 数据存储。它允许插入任意类型的内容,并通过hash-object返回一个键值,通过该键值可以在任何时候再取出该内容。它会将数据保存在 .git 目录并返回表示这些数据的键值。

  Git通过上层命令提交后生成几个对象,这些对象组成了git文件的数据结构。

 Git中有四种基本对象类型,组成了Git更高级的数据结构。

 1.tag对象:tag用于给某个上述类型的对象指配一个便于开发者记忆的名字, 通常用于某次commit。例如git commit -m "tag".

 2.tree对象:每个tree代表了一个目录的信息,包含了此目录下的blobs,子目录(对应于子trees),文件名、路径等元数据。因此,对于有子目录的目录,git相当于存储了嵌套的trees。

 3.blob对象:每个blob代表一个(版本的)文件,blob只包含文件的数据,而忽略文件的其他元数据,如名字、路径、格式等。

 4.commit对象:每个commit记录了提交一个更新的所有元数据,如指向的tree,父commit,作者、提交者、提交日期、提交日志等。每次提交都指向一个tree对象,记录了当次提交时的目录信息。一个commit可以有多个(至少一个)父commits。

详细内容可以参考《pro git》。

下面详细介绍一下blob对象如何被计算校验和,如何被存储。

git使用'blob ' + len(content) + '\0' + content作为文件内容
blob表示对象类型为blob类型,

len表示内容的长度

\0为空字节

其中'blob ' + len(content) + '\0' 来组成一个header,然后再将这个header与真正的内容content拼接起来,并计算拼接后的新内容的 SHA-1 校验和。Git 用 zlib 对数据内容进行压缩,最后将用 zlib 压缩后的内容写入磁盘。注意写入磁盘的不是文件的具体内容而是由header和content连接起来的内容通过SHA-1哈希出来的40位的摘要。取摘要的前两位作为目录,后面38位作为内容存储在磁盘上。

所以Git 以对象类型为起始内容构造一个文件头。然后添加一个空格,接着是数据内容的长度,最后是一个空字节 (null byte),接着用这个文件头和真正的内容拼接起来(不是文件名)计算校验和,然后用zlib对数据进行压缩,按照SHA-1 值的头两个字符作为子目录名称,剩余 38 个字符作为文件名保存压缩后的数据。这样就把一个文件存储到了git仓库中。

 估计也会有小伙伴和我一样好奇既然磁盘上存的是一个哈希值,那么具体的文件内容存在哪里了?其实git依赖于一个键/值对的数据库,这个hash值就是存储在数据库中的键,具体内容才是值。通过命令:git cat-file -p hashcode-key 可以取出文件内容。