iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
1
# Outline
一、前言
二、實驗
三、小結
A、待敘項目

# TL;DR
Git Object 有分為三種,Blob、Tree、Commit。Blob 是指實際檔案被封存後的 Git Object;Tree 是指一個紀錄當前目錄下有哪些 Blog 物件和 Tree 物件的檔案;Commit 物件是用來記錄 Commit 資訊的物件,也會特別指向一個 Tree 物件。

# Updated
2019-10-06: 更新文章結構

在雙十連假前,此系列文每天的發文時都會以最簡陳述為主,以求在繁忙的日常中,至少能先維持挑戰鐵人賽的進度,並且逐漸拓展思路與系列結構。預期會在國慶連假將本篇文章論述完整。

一、前言

昨天我們透過執行 git addgit commit 兩種指令,觀測 .git 這個儲存 Git 資訊的目錄會有什麼變化,發現 .git/objects 裡面多了許多以 SHA-1 產生的雜湊值為名的檔案,其實這些檔案就是所謂的 Git 物件。

Git 物件大抵 上分為三種,分別是:

  • Blob 物件
  • Tree 物件
  • Commit 物件

二、實驗

以昨天的範例來說,我們現在 .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 Object
  • b42533e 的 Commit Object 指向了 fdd2417 的 Tree Object
  • fdd2417 的 Tree Object 指向了:
    • a2beefd 的 Blob Object
    • 650e0dd 的 Tree Object
  • 650e0dd 的 Tree Object 又指向了 4228d0c 的 Blob Object
  • 4228d0c 的 Blob Object 的內容正是該 Commit 版本的 src/app.rb 檔案內容。

透過這些關係,我們得知了:

  • Commit Object 會指向前一個 Commit Object,透過這樣的方式形成了 Linked List,而這樣的關係最後變成線了一個不斷向前參考的鏈關係鏈。
  • 每個 Commit Object 會指向一個 Tree Object,而這個 Tree Object 紀錄的正是當前版本的專案根目錄的檔案與目錄,檔案透過 Blob 物件儲存起來,並且附上檔名與 SHA-1 值參考位址;目錄則透過另一個 Tree 物件儲存起來,而這個 Tree 物件可能又會包含 Blob 物件和其他的 Tree 物件,透過這種方式,我們就能重現這個 Commit 版本的目錄結構。

附錄 A、待敘項目

  • 將 Commit 的樹狀結構畫出示意圖
  • 詳細介紹 Tree Object 和 Blob Objec
  • 介紹 SHA-1 演算法

上一篇
Git Commit
下一篇
Git Reference
系列文
Git 其然,Git 其所以然31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言