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 看不出罢了。