专栏首页IT杂记Git 对象存储结构分析
原创

Git 对象存储结构分析

1. 前言

Git 对象有:blob (数据块), tree (目录树), commit (提交), tag (标签)。

本文通过一个示例,以blob为例来讨论对象的存储结构。示例采用的git版本为2.17

2. 实践讨论

2.1. 生成Blob对象文件

首先创建一个测试git仓库

$ mkdir hello
$ cd hello
$ git init

然后通过创建一个文件 test,test的内容为 "hello", 可以看到test文件的字节长度为6, 是因为创建文件的时候自动在行末加上了换行符\n。对文件其执行 git add , 可以看到在.git/objects目录下面生成了一个子目录ce,ce目录下面有个文件013625030ba8dba906f756967f9e9ca394464a。

$ echo "hello" > test
$ du -b test
6       test
$ git add test
$ find .git/objects/ -type f
.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a

该文件即为git为 test 文件数据内容生成的blob对象文件,该对象的SHA值为ce013625030ba8dba906f756967f9e9ca394464a.

至此,产生两个问题:

  1. 对象文件的数据结构是什么样的 ?
  2. 对象的SHA值又是如何生成的 ?

2.2. 对象数据结构及SHA值

根据 Git-Internals-Git-Objects 文中的描述:

首先,对象文件数据结构如下图:

git-object-storage.png
  • content: 表示数据内容
  • head: 对象头部信息
    • object type:对象类型,可选值为 blob, tree, commit
    • whitespace: 一个空格字符
    • content byte size:数据内容的字节数字符串
    • NUL:空字符,ASCII码值为0

然后, 对象的SHA值就是对上面这个数据结构执行SHA1 hash摘要算法得到的。

2.3. 动手验证

根据2.2中的规则来编码对2.1中的test文件内容生成一个SHA值,看是否和git生成的SHA值一致?

    // object content
    String content = "hello\n";
    byte[] contentBytes = content.getBytes();

    ByteBuffer buf = ByteBuffer.allocate(1024);


    buf.put("blob".getBytes()); // object type
    buf.put((byte) ' ');        // whitespace
    buf.put(Integer.toString(contentBytes.length).getBytes());  // content byte size numeric string
    buf.put((byte) 0);          // NUL
    buf.put(contentBytes);      // content

    buf.flip();

    // whole object bytes
    byte[] objectBytes = new byte[buf.remaining()];
    buf.get(objectBytes);

    // Execute SHA1 hash digest
    MessageDigest md = MessageDigest.getInstance("SHA1");
    byte[] shaBytes = md.digest(objectBytes);

    // Show in hex
    String shaHex = Hex.encodeHexString(shaBytes);
    System.out.println(shaHex);

上述代码输出:ce013625030ba8dba906f756967f9e9ca394464a

和 2.1 中git生成的SHA值一致,2.2 中数据结构和SHA值的生成得到验证。

2.4. 对象压缩

根据 Git-Internals-Git-Objects 可知git 对象文件是经过Zlib::Deflate.deflate 压缩存储的。

$ cat .git/objects/ae/a941d707291bf3f2103c096479b068f7bed4f8
x☺K
cat: write error: Input/output error

可以看到通过cat命令是无法直接输出内容的。

        InputStream is = new InflaterInputStream(new FileInputStream(
                ".git\\objects\\ce\\013625030ba8dba906f756967f9e9ca394464a"));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int b = 0;
        while ((b = is.read()) != -1) {
            baos.write(b);
        }

        byte[] res = baos.toByteArray();
        System.out.println(new String(res));

        is.close();
        baos.close();

通过如上代码可输出对象的数据结构:

blob 6hello

注其中包括不可见字符NUL和换行符。

通过git cat-file命令可以直接查看对象的数据内容:

$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello

3. 总结

  1. 对象数据结构为:
git-object-storage.png
  1. 对象SHA值为对( 1. 对象数据结构)执行SHA1消息摘要算法生成;
  2. 对象存储结构为:对(1. 对象数据结构)进行deflate压缩后存储;

4. 参考资料

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Git 对象存储结构分析

    囚兔
  • Mapreduce 任务提交源码分析1

    提交过程 一般我们mapreduce任务是通过如下命令进行提交的 $HADOOP_HOME/bin/hadoop jar $MR_JAR $MAIN_CLASS...

    囚兔
  • Websocket HandShake Sec-WebSocket-Accept 生成策略

    先阅读http://tools.ietf.org/html/rfc6455 规范,然后实践。 思路如下:     服务端先获得请求头部的Sec-WebSock...

    囚兔
  • Git 对象存储结构分析

    囚兔
  • 10.4 Git 内部原理 - 包文件

    让我们重新回到示例 Git 版本库的对象数据库。 目前为止,可以看到有 11 个对象——4 个数据对象、3 个树对象、3 个提交对象和 1 个标签对象:

    shaonbean
  • Git常用命令、分支管理

    代码托管中心的任务:维护远程库 局域网环境下:GitLab服务器 外网环境下:码云

    桑鱼
  • Git存管代码,实例演示

    右键Git Bash的属性,删除目标后面的" --cd-to-home",起始位置设置我们的工作空间,这样每次我们打开就会自动进入进来了。

    小蓝枣
  • Git之 基本常用命令

       git init          把当前的目录变成可以管理的git仓库,生成隐藏.git文件。

    shirayner
  • Git教程——安装和初步使用

    用户2149234
  • iOS面试中被面试官问到的问题答案(一)

    2016-03-1016:30:14 发表评论 1,091℃热度 1.请你谈谈static和宏定义的区别。什么时候用static什么时候用宏定义。 让你声...

    timhbw

扫码关注云+社区

领取腾讯云代金券