解剖 .git 資料夾 part. 2 - Blob Object

在前面的 解剖 .git 資料夾 part. 1 - Git Init 我們已經初步瞭解了 .git 資料夾初始化後的結構,但是其中 objects 這個資料夾是空的,就讓我們來看看 執行 git add 後是如何將檔案存放在 objects 資料夾下

Blob object 介紹

由於目前我們還沒有任何的檔案,讓我們新增一個 README.md

echo "This is readme." > README.md

再來執行 git add README.md 來將他加到 git 的索引裡,完成後 git status 的結果應該會像下面這樣:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

這時候我們可以來看一下 .git/objects 下的檔案長什麼樣子

objects/
  ├─ pack/
  ├─ info/
  └─ 52/
     └─ cb6cdb81a64344370c918a301eb153035f915a

blob object 內容

這時候多了一個名字叫 52 的資料夾,底下有一個檔案叫 cb6cdb81a64344370c918a301eb153035f915a,如果你把他打開會發現內容是看不懂的

$ xxd .git/objects/52/cb6cdb81a64344370c918a301eb153035f915a
00000000: 7801 4bca c94f 5230 3463 08c9 c82c 5600  x.K..OR04c...,V.
00000010: a2a2 d4c4 94dc 543d 2e00 5ee3 0781       ......T=..^...

原因是所有在 object file 下的檔案都會經過 zlib 壓縮後存放,解壓縮後我們可以看到 object file 的內容是由以下的結構所組成

  • blob + 空格 + 檔案大小 + zero btye + 原始檔案的內容

比較特別的是檔案大小會用十進位來儲存,會直接寫 16 的 ASCII code 而不是十六進位的 00 10 (我們檔案在最後面有換行符號,所以 size 是 16)

$ openssl zlib -d -in .git/objects/52/cb6cdb81a64344370c918a301eb153035f915a | xxd
00000000: 626c 6f62 2031 3600 5468 6973 2069 7320  blob 16.This is
00000010: 7265 6164 6d65 2e0a                      readme..

git 其實也有提供工具來幫忙解壓縮和印出內容

我們需要先得到完整的 object hash 兩碼資料夾 + 檔名 = 52cb6cdb81a64344370c918a301eb153035f915a

當我們有了 object hash 之後可以用

  • git cat-file -t <HASH> 來印出 object 類型 blog
  • git cat-file -p <HASH> 來印出內容 This is readme.
  • git cat-file -s <HASH> 來印出檔案大小 16

blob hash 由來

這個長長的 hash 其實是用未壓縮的檔案內容做 SHA-1 hash 之後得到的結果,我們可以用 sha1sum 指令來測試

$ openssl zlib -d -in .git/objects/52/cb6cdb81a64344370c918a301eb153035f915a | sha1sum
52cb6cdb81a64344370c918a301eb153035f915a *-

由於是依照檔案內容來計算出來的 hash 當 object 檔名,如果有內容完全一樣的檔案就可以直接共用來省空間,另外用兩碼來切分資料夾也可以避免在同一個資料夾中有過多的檔案,有助於提高尋找和管理的效率

BTW 如果想要用 SHA-256 演算法來算 object hash 也是可行的,只要在 git init 的時候用 --object-format=sha256 來指定即可

這篇就先講到這邊,我們接下來可以來看一下 .git/index 這個檔案的內容

如果覺得內容有幫助可以給個拍手~ 

留言

這個網誌中的熱門文章

unit testing 的第一步:使用 gcov/lcov 統計 c++ project 的 testing coverage

在 python 中透過 ctypes 執行 C++ library 的 class

在 blogger 寫 markdown 最接近完美的辦法