『現學現忘』Git物件 — 17、Commit物件

繁華似錦Fighting發表於2022-04-27

1、Commit物件介紹

現在來介紹最後一種Git物件commit物件,也叫提交物件。

提交物件可以理解為是對樹物件的一層封裝,提交資訊包括基於當前暫存區中索引檔案生成的tree物件,還有包含了提交時間,提交者資訊,作者資訊,以及提交備註等內容,更重要的是裡面還包含了父提交的ID,由此就可以形成Git提交的有向無環圖。(是鏈式的關係,把所有commit物件關聯起來)

即:commit物件通常指向一個 tree 物件,並且封裝了檔案的提交時間,提交者資訊,作者資訊,提交備註,以及父提交引用等資料。

下面是commit物件的儲存結構:

image

2、Commit物件說明

我們通過練習來說明commit物件,接著用前面Tree物件的本地版本庫。

(1)建立一個commit物件

我們可以通過呼叫commit-tree命令建立一個提交物件,為此需要指定一個樹物件的SHA-1值,以及該提交的父提交物件。

說明:使用commit-tree命令來建立提交物件,一般都需要和父提交進行關聯,如果是第一次將暫存區的檔案索引資料提交到本地版本庫,那麼該提交操作就不需要指定父提交物件。

1)我們可以先檢視一下此時Git本地庫中的物件,如下

.git/objects/01/ab2a43b1eb150bcf00f375800727df240cf653 # 第三個tree樹物件
.git/objects/0c/1e7391ca4e59584f8b773ecdbbb9467eba1547 # test.txt第二個版本(blob物件)
.git/objects/16/3b45f0a0925b0655da232ea8a4188ccec615f5 # 第二個tree樹物件
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt第一個版本(blob物件)
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # 第一個tree樹物件
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt第一個版本(blob物件)

2)我們通過第一個樹物件,建立一個commit物件

# 1.做提交操作,建立一個commit物件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ echo 'first commit' | git commit-tree d8329f
3ceba95d3cd9cce982d31e41e3b995ece72f755d

# 2.確定該物件型別
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ git cat-file -t 3ceba95d3c
commit

# 3.檢視該物件內容
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ git cat-file -p 3ceba95d3c
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author sun_wk <sun_wk@126.com> 1618190880 +0800
committer sun_wk <sun_wk@126.com> 1618190880 +0800

first commit

說明:

  • tree:表示該commit物件所指向的tree物件的索引
  • author:表示該檔案的作者。
  • committer:表示該檔案的提交者。
  • first commit:這段文字是提交備註。(備註與前面留空一行)
  • 因為是第一次進行commit提交操作,所以沒有父提交資訊。
  • 1618190880 +0800:表示時間,一個時間戳。

即:commit物件的格式很簡單:指明瞭該時間點專案快照的頂層樹物件、作者/提交者資訊(從 Git 設定的 user.nameuser.email中獲得),以及當前時間戳、留空一行,最後是提交註釋。

提示:git commit-tree命令不但生成了提交物件,而且會將對應的快照(樹物件)提交到本地庫中。

(2)建立第二個commit物件

根據第二個tree物件和第一個commit物件,來建立第二個commit物件。

通過-p選項指定父提交物件。

# 1.建立第二個commit物件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ echo 'second commit' | git commit-tree 163b45f0a09 -p 3ceba95d3cd9cc
60e1c209e9de87314ec47cf28e61de8df5362fe6

# 2.檢視該物件內容
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ git cat-file -p 60e1c209e9de8
tree 163b45f0a0925b0655da232ea8a4188ccec615f5
parent 3ceba95d3cd9cce982d31e41e3b995ece72f755d
author sun_wk <sun_wk@126.com> 1618193286 +0800
committer sun_wk <sun_wk@126.com> 1618193286 +0800

second commit

提交物件的格式很簡單:

它先指定一個頂層樹物件,代表當前專案快照;

然後是可能存在的父提交;

之後是作者/提交者資訊(依據你的 user.nameuser.email 配置來設定,外加一個時間戳);

留空一行,最後是提交註釋。

第三個commit提交,同上,這裡就不演示了。

3、本地庫中物件之間的關係

我們可以檢視一下此時Git本地庫中的物件

.git/objects/01/ab2a43b1eb150bcf00f375800727df240cf653 # 第三個tree樹物件
.git/objects/0c/1e7391ca4e59584f8b773ecdbbb9467eba1547 # test.txt第二個版本(blob物件)
.git/objects/16/3b45f0a0925b0655da232ea8a4188ccec615f5 # 第二個tree樹物件
.git/objects/3c/eba95d3cd9cce982d31e41e3b995ece72f755d # 第一個commit提交物件
.git/objects/46/ab608799a0e65e970b67b9b52f6c1407c39036 # 第三個commit提交物件
.git/objects/60/e1c209e9de87314ec47cf28e61de8df5362fe6 # 第二個commit提交物件
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt第一個版本(blob物件)
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # 第一個tree樹物件
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt第一個版本(blob物件)

可以從上面看到,此時的本地版本庫中共有9個物件,三個blob物件,三個tree物件,三個commit物件。

他們之間的關係如下圖:

image

4、總結

  1. 提交是我們經常使用的Git動作,每次提交操作都指向一個樹物件,同時會產生一個commit物件。
    即:一個commit物件包含了一個tree物件,這個tree物件記錄了在那個時間點,專案包含了什麼資料夾和什麼檔案。
  2. 一個提交物件可以有一個或者多個父提交。
  3. 每次commit操作都會基於當前索引檔案index新建tree物件。那麼當前索引檔案,是在上次提交的基礎上更新來的,所以每次提交產生的commit物件,與其他的commit物件,都有前後關係或者稱為父子關係。
  4. 對於我們來說,不需要直接訪問blob物件和tree物件,我們直接訪問commit物件就可以了。
    即:commit物件對應的tree物件下面,又包含了小的tree物件和blob物件,子的tree物件一層層展開,最後葉子節點就是一個個blob物件,也就是一個個檔案。

到這裡,我們就能夠清楚的瞭解,什麼叫一個Git版本。tree物件才是一次專案版本的快照,提交物件是對tree物件的一次封裝。

即:

  • 專案的快照就是一個樹物件。
  • 專案的版本就是一個提交物件。

而且Git的每一個版本,儲存的不是增量,而儲存的是當前專案的快照。同時objects目錄中相當於存放了專案的所有歷史記錄,回滾就相當的方便了,找到對應的commit物件的hash就可以了。

5、練習

請問下圖中包含多少個tree物件和blob物件?

image

一共包含兩個tree物件,一個blob物件,一個commit物件。

說明:

  • 一個commit物件一定對應一個tree物件(這個tree物件應該是一個完整專案倉庫的快照)
  • doc目錄下有一個blob物件,也就是readme檔案。

6、本文用到的命令總結

Git底層命令:

  • git commit-tree:生成一個commit物件。
  • git cat-file -t 鍵:檢視Git物件的型別。
  • git cat-file -p 鍵:檢視Git物件的內容。

參考:

相關文章