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