Git 有四種 type (類型) 的物件:blob、tree、commit 和 tag。
本篇主要先來講解 Blob 物件與 Tree 物件。
本篇會使用到兩個過去沒使用的指令:
git hash-object
、git cat-file -t
未來有機會可以介紹!
說明:Git 將檔案內容轉成二進制,並產生 SHA-1 編號後儲存的物件。
產生時機:git add
加至暫存區時,在 .git 目錄裡產生一個 Blob 物件,並依照規則擺放在它的目錄裡。
用途:存放檔案的「內容」。
⚠️ 注意:此處指的是檔案裡面的內容,即可能編輯的東西,而非檔案本身。
🛠 實際操作|建立 Blob 物件 - 建立一個檔案並加入至 Git 控管
首先先建立一個工作目錄,並進行 Git 版本控制,執行 git init 初始儲存庫。
$ git init # 初始化儲存庫
初始化新的數據庫時,Git 會在 .git 目錄中初始化 objects 目錄,並在裡面建立 pack 和 info 子層的空目錄。
假設今天我們建立了一個 demo.html 檔案,並在檔案裡加上內容是 " hello world ! " 字串
$ touch index.html # 新增一個 index.html 檔案
前幾篇的文章我們可以知道,目前檔案還沒有被 Git 控管,因此我們可以透過指令將檔案加至暫存區。
輸入指令執行將檔案加至暫存區,並檢查狀態
$ git add . # 將所有檔案加入暫存區
$ git status # 檢查檔案狀態
👉 這時候,Git 會在 .git 目錄下建立 blob 物件用來儲存檔案內容。
可以從 objects 目錄中發現,多了兩個資料夾。更進一步查看會發現是個 38 字元的檔案。
資料夾的 2 個字元與檔案的 38 個字元合起來代表這個 Blob 物件的 SHA-1 值,它是透過「規則」計算出來的。
也可以透過手動執行 git hash-object
指令來計算
$ echo 'hello world!' | git hash-object -w --stdin # 將資料儲存在 .git 目錄中,並取得 SHA-1 編號
-w
參數
將物件加入 .git/objects 目錄內,並輸出相對應的 SHA-1 值
如果沒有加上 -w
參數,只會輸出 SHA-1 值,並不會儲存物件
--stdin
參數
從 stdin 讀取內容(stdin - standard input, 標準輸入)
如果沒有使用 --stdin
參數,hash-object
指令預設會從檔案中讀取,因此需要在指令後面加上指定的檔案路徑。
執行hash-object
指令後,會出現 40 個字元,這就是 SHA-1 值,是由儲存的內容和 header 資訊所計算出來的。
目錄規則:
子目錄 - 前 2 個字元
檔名 - 剩餘的 38 字元
💡 使用 2 個字元作為子目錄,是避免讓 .git/objects 目錄因為檔案過多而降低效能。
這個檔案內容因為已經被壓縮過,所以我們如果使用一班的文字編輯器是無法得知內容,不過可以使用 git cat-file
指令察看物件資訊
$ git cat-file -t a0423 # 查看物件資訊(型態)
-t
參數,代表要查看的是內容的物件型態,因此得到的回饋會是 blob 物件。
如果想要看這個物件的內容
的話,可以改用 -p
參數。
$ git cat-file -p a0423 # 查看物件資訊(內容)
這時候 Git 的回報就是當初我手動儲存的文字內容啦!
總結上述操作得知:
Blob 物件的檔名由
SHA-1 演算法
決定;Blob 的內容則是壓縮演算法
決定。
有了 Blob 物件可以存內容之後,Git 也提供了可以存檔名、資料夾名稱的物件,此物件及為「Tree 物件」。
關於 Tree 物件的說明:
Tree 物件與 Blob 物件相同,都是以 SHA-1 雜湊值作為檔名,儲存二進制內容。但兩著的差異在於,Blob 物件主要是儲存我們的檔案「內容」,而 Tree 物件則是儲存「檔名」,而 Tree 物件裡不一定只有包著 Blob 物件,同時也可以包含另一個 Tree 物件。
了解 Tree 物件的內容後,我們大致可以了解 Tree 可以幫助我們儲存檔案的名稱、目錄的名稱、檔案權限,也因為 Tree 物件同時可以紀錄 Tree 物件與 Blob 物件之間的關聯性,因此我們可以透過 Tree 物件來找到子目錄以下的一些檔案內容或檔名。
下圖說明 Tree 物件與 Blob 物件之間的關聯性:
總結整理:
Blob 儲存檔案「內容」、Tree 儲存檔案「名稱」