[Git 原理] Git 物件儲存格式

Git 有四種物件,分別是 Blob (binary large object) 物件、Tree 物件、Commit 物件以及 Tag 物件。本文會介紹這四種物件的檔案儲存格式。

這四種物件的檔案儲存內容皆是以 header + content 的形式儲存。這裡的 + 指的是檔案的內容前面的 bytes 為 header,其後緊接著物件的 content。

Header 格式

header 的格式為:"[object type] [content.bytesize]\0"

注意 [object type][content.bytesize] 中間有一個空白字元。

上面用括號括起來是要強調它是純字串,本文會遵循這樣的慣例。

\0 是 null character,而 object type 可以填 blobtreecommittag,看你現在的物件是哪一種類型的 Git 物件。

物件檔名

Git 物件被儲存成檔案時,其檔名皆是以這樣的規則計算:

  1. 將 header + content 經由 SHA-1 演算法算出一個 Hash 值
  2. Hash 值前兩個字元為目錄名稱,後面 38 個字元為檔案名稱

所有 Git 物件都是儲存在 .git/objects 目錄底下,所以會在 .git/objects 目錄底下以 Hash 值前兩個字元創立一個子目錄,然後在這個子目錄底下放儲存的 Git 物件(檔名為 Hash 值後 38 個字元)。

檔案儲存內容

在本文開頭有提到 Git 物件的儲存內容為 header + content,但 Git 並不是直接把 header + content 的 raw bytes 儲存到檔案上,而是會先將 header + content 經由 zlib 壓縮後再儲存。

上面介紹完 header 的格式,接著要介紹每個物件的 content 是什麼內容。

Blob 物件

Blob 物件代表的就是你要給 Git 做版控的檔案,所以 Blob 物件的 content 即為那個檔案的內容。

Tree 物件

Tree 物件代表的就是目錄結構,用來標示這個目錄底下有哪些 Blob 物件跟 Tree 物件(代表子目錄)。

因此, Tree 物件的 content 是由一至多個 tuple 所組成,每個 tuple 都是這樣的格式 (file type, filename, hash):"[file type] [filename]\0" [hash]

注意 file type 跟 file name 中間有一個空白字元。

file type 如果是 100644 代表的就是一般的檔案、040000 則代表是目錄(tree 物件)。

上面的 hash 指的是對應物件的 SHA-1 值。注意它不是以字串的形式儲存,而是 SHA-1 演算法算出來的 raw bytes。[hash] 跟前面字串中間的空白只是為了好閱讀,實際檔案儲存時中間並沒有空白字元。

Commit 物件

Commit 物件的 content 格式如下,直接用一個範例說明:

"tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF
[parents]
"author Alice <[email protected]> 1234567890 -0800" LF
"committer Bob <[email protected]> 1234567890 -0800" LF
LF
"Shakespeare" LF

上面的 LF 是指 \n 換行字元,這段用 LF 代表 \n 字元是為了讓閱讀更清楚。"Shakespeare" 就是 commit 的訊息內容。(注意:commit message 結尾不一定要加 \n 換行字元。)

可以注意到上面 tree 物件的 SHA-1 值是 Hex string 而不是 raw bytes。

1234567890 指的是 commit 的時間,此為距離 1970 年 1 月 1 日(UTC)的秒數。

-0800 是 time zone。

[parents] 指的是 commit 的 parents,如果一個 commit 沒有 parents 代表它是第一個 commit。commit 可能有兩個 parents,例如 merge commit。

每個 parent 的格式為:"parent c3c324eff2a57c947622a3711909d5589f4e1f3d" LF

注意 parent 的 SHA-1 值一樣是 Hex string。

Tag 物件

請參考:What is the format of a git tag object and how to calculate its SHA?

參考資料

  1. 10.2 Git Internals - Git Objects
  2. 10.3 Git Internals - Git References
  3. Git Magic - Chapter 8. Secrets Revealed
  4. What is the format of a git tag object and how to calculate its SHA?
  5. What is the file format of a git commit object data structure?
Show Comments