寫作背景
進來在閑暇的時間裡在看一些關係P2P網路的拓撲發現的內容,重點關注了Markle Tree的知識點,在一篇文章裡(https://www.sdnlab.com/20095....),發現了了一句話
“Merkle DAG的一個常見例子就是Git存放庫”,於是尋找了一些關於git存放庫的原理,先整理如下。僅供自己和大家參考。
Git存放庫解析
當時我的疑問:
- git怎麼儲存資料的,如何能根據儲存的資料可以很精確的回退到制定的版本?
- git儲存和docker的儲存機制類似嗎?是不是都是分層的儲存?
- git如果不是分層,每次提交都儲存起來,那麼資料量大了會怎麼辦?
解惑
我們的解惑路線是,從建立一個本地git倉庫開始,一步一步增加資料和提交,觀察內容的具體變化。
知識點學習了之後,我們怎麼去驗證呢?
- 使用
git cat-file
對我們提交的內容進行驗證。
- 我進行了兩次commit,一次是完全建立的一個README.md檔案,裡面是有一行資料(### You Know);第二次commit,建立一個test.py檔案和在README.md中新添加了一些資料;
git cat-file -t
查看對象的類型,git cat-file -p
優雅的方式列印對象的內容。
- 使用
git log --pretty=oneline
查看我的兩次提交
- 使用
git cat-file -t 172b54c8cd3eedca2fc301374286c2cb807d674f
查看第一次提交的類型
- 使用
git cat-file -p 172b54c8cd3eedca2fc301374286c2cb807d674fe
查看第一次提交的內容
- 使用
git cat-file -p 8b0c4fe1567a463214c09334b54977e0114c90fe
查看第一次提交的tree對象,可以看到tree對象中存放的是一個blob對象,就是我們第一次提交建立的檔案README.md
- 使用
git cat-file -p 67aeba604cea61ec63d19db0706b19d846c65ba4
查看第一次提交的blob對象的內容為### You Know
- 使用
git cat-file -p 03543a4c19023da01b5114d7f7a614d95a1bf084
查看第二次提交的內容
- 使用
git cat-file -p 03543a4c19023da01b5114d7f7a614d95a1bf084
查看第二次提交的tree對象內容,包括修改的內容和新增的內容
- 使用
git cat-file -p 03543a4c19023da01b5114d7f7a614d95a1bf084
查看第二次提交的README.md blob對象內容,可以看到是整個檔案的全部內容,而不是僅僅包含修改的資料。
總結問題的答案
- git的資料存放區資料結構是索引值類型,分為4個對象,並且每次提交都是整個檔案的儲存,而不是分層的增加儲存,所以這樣會導致儲存的資料量很大,那git用的方法是使用zlib對資料進行壓縮,所以我們開啟儲存的檔案是這樣的資料,那我們都是用cat-file命令來查看的,怎麼才能這些內容是經過zlib壓縮過的呢?
- 我用GO語言寫了一個簡單的程式,來驗證這些資料是經過zlib壓縮之後的,運行這個程式的時候帶上你要查看git對象的檔案路徑,就可以看到被還原的內容了;
GO代碼
package mainimport ( "bytes" "compress/zlib" "fmt" "io" "io/ioutil" "os")//進行zlib壓縮func DoZlibCompress(src []byte) []byte { var in bytes.Buffer w := zlib.NewWriter(&in) w.Write(src) w.Close() return in.Bytes()}//進行zlib解壓縮func DoZlibUnCompress(compressSrc []byte) []byte { b := bytes.NewReader(compressSrc) var out bytes.Buffer r, _ := zlib.NewReader(b) io.Copy(&out, r) return out.Bytes()}func main() { args := os.Args if args == nil || len(args) < 2{ fmt.Println("Should input zlib file path.") return } b, err := ioutil.ReadFile(args[1]) if err != nil { fmt.Print(err) } fmt.Println(string(DoZlibUnCompress(b)))}
總結
- 文章是參考了很多前輩部落格基礎上寫來的, 也有自己的實踐,所以很有必要記錄下來。
- 有問題就想辦法去理解和解決,並通過動手實踐驗證。