Git 数据是怎么存储的

git 的数据存储数据结构是键值类型,git中底层生成了4中数据的对象

  • commit:commit 对象指向一个 tree 对象,并且带有相关的描述信息.
  • tree: 可以看作一个目录
  • blob: 通常用来存储文件的内容
  • tag:tag 对象包括一个对象名(SHA1签名)、对象类型、标签名、标签创建人的名字(“tagger”), 还有一条可能包含有签名(signature)的消息

上图出自 sixgo-Git数据存储的原理浅析

举例提交

> git commit -m 'chore: LAO'
[master (root-commit) 4b9fc1a] chore: LAO
 2 files changed, 57 insertions(+)
 create mode 100644 index.html
 create mode 100644 test.js

> git log
commit 4b9fc1a52e74ed4e408c4994296a1f960533f48b (HEAD -> master)
Author: Ever-lose <ever-lose@foxmail.com>
Date:   Mon May 4 19:28:20 2020 +0800

    chore: LAO

使用 git cat-file

# 获取此 commitid 的类型,是 commit
> git cat-file -t 4b9fc1a52e74ed4e408c4994296a1f960533f48b
commit

# 获取 tree
> git cat-file -p 4b9fc1a52e74ed4e408c4994296a1f960533f48b
tree 5937ab7ef5b6aaf4aad3ad4b09bfef7b97ee6e39
author Ever-lose <ever-lose@foxmail.com> 1588591700 +0800
committer Ever-lose <ever-lose@foxmail.com> 1588591700 +0800

chore: LAO

# 获取 blob
> git cat-file -p 5937ab7ef5b6aaf4aad3ad4b09bfef7b97ee6e39
100644 blob 0f7b3babfbcec4778ef50337115faf87e67fc682    index.html
100644 blob 39a772dd49196db8bfffb50a58bd10bac3dcb4ab    test.js

# 获取 index.html 里的 blob 内容
> git cat-file -p 0f7b3babfbcec4778ef50337115faf87e67fc682
<!DOCTYPE html>
<html lang="en">
<head>
... 省略

由此可知 git 存储是存储一整个文件的。并且能注意到项目目录的 .git\objects 下有个目录叫 4b,里面有个叫 9fc1a52e74ed4e408c4994296a1f960533f48b 的文件,其实 4b 取自 commitId 里前两个字符,而 9fc1a52e74ed4e408c4994296a1f960533f48b 自然就是 commitId 里剩余的 38 个字符了。文件是二进制的,打开也看不明白。

第二次提交,笔者就修改了 index.html 里的第一行

> git commit -m 'chore: 第二次提交'
[master bd07fbb] chore: 第二次提交
 1 file changed, 1 insertion(+)

# 查看这两次提交
> git log --pretty=oneline
bd07fbb7f181f868191862e542da1636109e4e46 (HEAD -> master) chore: 第二次提交
4b9fc1a52e74ed4e408c4994296a1f960533f48b chore: LAO

# 获取 tree,注意下面 parent 是第一个 commitId
> git cat-file -p bd07fbb7f181f868191862e542da1636109e4e46
tree 2df4d0cfd56341eeecb705a6c5c3eaebb66d4c63
parent 4b9fc1a52e74ed4e408c4994296a1f960533f48b
author Ever-lose <ever-lose@foxmail.com> 1588592528 +0800
committer Ever-lose <ever-lose@foxmail.com> 1588592528 +0800

chore: 第二次提交

# 获取 blob
>  git cat-file -p 2df4d0cfd56341eeecb705a6c5c3eaebb66d4c63
100644 blob 114653874c6ed19c24c15f71532199aece94799d    index.html
100644 blob 39a772dd49196db8bfffb50a58bd10bac3dcb4ab    test.js

# 查看 index.html 的 blob 对象,下文的 <!-- 测试提交 --> 就是修改的内容
> git cat-file -p 114653874c6ed19c24c15f71532199aece94799d
<!-- 测试提交 -->
<!DOCTYPE html>
<html lang="en">

结论

git 的数据存储数据结构是键值类型,git中底层生成了4中数据的对象。

每个 commit,git 都要存储所有的文件内容,所以这样会导致存储的数据量很大。所以检出时使用 git clone xxxrepo --depth 1 会有奇效。

因为数据量大,git 自然不会采用明文传递文件了,所以 blob 内容是采用 zlib 进行数据压缩了的,只是我们用 git cat-file 看不出罢了。

参考

sixgo-Git数据存储的原理浅析

posted @ 2020-05-04 20:12  Ever-Lose  阅读(1205)  评论(0编辑  收藏  举报