# Outline
一、前言
二、實驗
三、小結
A、待敘項目
# TL;DR
Git Object 有分為三種,Blob、Tree、Commit。Blob 是指實際檔案被封存後的 Git Object;Tree 是指一個紀錄當前目錄下有哪些 Blog 物件和 Tree 物件的檔案;Commit 物件是用來記錄 Commit 資訊的物件,也會特別指向一個 Tree 物件。
# Updated
2019-10-06: 更新文章結構
在雙十連假前,此系列文每天的發文時都會以最簡陳述為主,以求在繁忙的日常中,至少能先維持挑戰鐵人賽的進度,並且逐漸拓展思路與系列結構。預期會在國慶連假將本篇文章論述完整。
昨天我們透過執行 git add
和 git commit
兩種指令,觀測 .git
這個儲存 Git 資訊的目錄會有什麼變化,發現 .git/objects
裡面多了許多以 SHA-1 產生的雜湊值為名的檔案,其實這些檔案就是所謂的 Git 物件。
Git 物件大抵 上分為三種,分別是:
以昨天的範例來說,我們現在 .git/objects
下有這幾個檔案:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ tree .git/
.git/
├── ......
├── objects
│ ├── a2
│ │ └── beefd59223ea16000788d77e62f96bdaf23c7c
│ ├── f4
│ │ └── 7eca7b5d0a157583076c66d470b1eb032822ac
│ └── fa
│ └── 5e6af79e30fc26ab4acbd96388fde22b4c2f36
└── ......
透過 git cat-file
去還原這些 Git Object 的內容,正好是三種類型的 Git Object 各佔一個:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
# Git Object: Blob
$ git cat-file -p a2beefd59223ea16000788d77e62f96bdaf23c7c
# My Project
# Git Object: Tree
$ git cat-file -p fa5e6af79e30fc26ab4acbd96388fde22b4c2f36
100644 blob a2beefd59223ea16000788d77e62f96bdaf23c7c README.md
# Git Object: Commit
$ git cat-file -p f47eca7b5d0a157583076c66d470b1eb032822ac
tree fa5e6af79e30fc26ab4acbd96388fde22b4c2f36
author Ruoshi Lin <me@fntsr.tw> 1568993969 +0800
committer Ruoshi Lin <me@fntsr.tw> 1568993969 +0800
我們會看到 Blob 物件還原後顯示的正是原本檔案的內文,透過內容,我們看以得知這個檔案正是 README.md
被 Git 儲存的 Git Object。
至於 Tree 物件和 Commit 物件,為了能更瞭解其實際用途,我們再多下一個 commit,這個 commit 的變動包含了建立了一個子目錄:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ mkdir src
$ echo "puts 'hello, world'" > src/app.rb
$ git commit -m "Add app program"
然後觀測做了這樣的操作後,.git
有了什麼樣的變化:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
$ tree .git/
.git/
├── COMMIT_EDITMSG
├── HEAD
├── index
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 42
│ │ └── 28d0cd48b9ed4395a23641c6292442b1af4994
│ ├── 65
│ │ └── 0e0dd9f112a14a0be19b3143a5eacee882e1bb
│ ├── a2
│ │ └── beefd59223ea16000788d77e62f96bdaf23c7c
│ ├── b4
│ │ └── 2533e454e5d2692d7f0d96e2a8ed699de200e8
│ ├── f4
│ │ └── 7eca7b5d0a157583076c66d470b1eb032822ac
│ ├── fa
│ │ └── 5e6af79e30fc26ab4acbd96388fde22b4c2f36
│ └── fd
│ └── d241767aec1614be16cd718e5baae6ba0cab4b
└── refs
└── heads
└── master
接著透過 cat-file
還原多出來的 Git Object,看是多出了怎樣的內容:
# [Repo] f47eca7 @ dot-git
# [Repo] 5626a0e @ lab
# Location: ~/how-git-works-lab
# Git Object: Commit
$ git cat-file -p b42533e454e5d2692d7f0d96e2a8ed699de200e8
tree fdd241767aec1614be16cd718e5baae6ba0cab4b
parent f47eca7b5d0a157583076c66d470b1eb032822ac
author Ruoshi Lin <me@fntsr.tw> 1569078100 +0800
committer Ruoshi Lin <me@fntsr.tw> 1569078100 +0800
Add app program
# Git Object: Tree
$ git cat-file -p fdd241767aec1614be16cd718e5baae6ba0cab4b
100644 blob a2beefd59223ea16000788d77e62f96bdaf23c7c README.md
040000 tree 650e0dd9f112a14a0be19b3143a5eacee882e1bb src
# Git Object: Tree
$ git cat-file -p 650e0dd9f112a14a0be19b3143a5eacee882e1bb
100644 blob 4228d0cd48b9ed4395a23641c6292442b1af4994 app.rb
# Git Object: Blob
$ git cat-file -p 4228d0cd48b9ed4395a23641c6292442b1af4994
puts 'hello, world'
最後我們整理出這樣的關係:
b42533e
的 Commit Object 指向了 f47eca7
的 Commit Objectb42533e
的 Commit Object 指向了 fdd2417
的 Tree Objectfdd2417
的 Tree Object 指向了:
a2beefd
的 Blob Object650e0dd
的 Tree Object650e0dd
的 Tree Object 又指向了 4228d0c
的 Blob Object4228d0c
的 Blob Object 的內容正是該 Commit 版本的 src/app.rb
檔案內容。透過這些關係,我們得知了: