1、Commit對象介紹
現(xiàn)在來介紹最后一種Git對象commit對象,也叫提交對象。
提交對象可以理解為是對樹對象的一層封裝,提交信息包括基于當(dāng)前暫存區(qū)中索引文件生成的tree對象,還有包含了提交時間,提交者信息,作者信息,以及提交備注等內(nèi)容,更重要的是里面還包含了父提交的ID,由此就可以形成Git提交的有向無環(huán)圖。(是鏈?zhǔn)降年P(guān)系,把所有commit對象關(guān)聯(lián)起來)
即:commit對象通常指向一個 tree 對象,并且封裝了文件的提交時間,提交者信息,作者信息,提交備注,以及父提交引用等數(shù)據(jù)。
下面是commit對象的存儲結(jié)構(gòu)

2、Commit對象說明
我們通過練習(xí)來說明commit對象,接著用前面Tree對象的本地版本庫。
(1)創(chuàng)建一個commit對象
我們可以通過調(diào)用commit-tree命令創(chuàng)建一個提交對象,為此需要指定一個樹對象的SHA-1值,以及該提交的父提交對象。
說明:使用
commit-tree命令來創(chuàng)建提交對象,一般都需要和父提交進(jìn)行關(guān)聯(lián),如果是第一次將暫存區(qū)的文件索引數(shù)據(jù)提交到本地版本庫,那么該提交操作就不需要指定父提交對象。
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)我們通過第一個樹對象,創(chuàng)建一個commit對象
# 1.做提交操作,創(chuàng)建一個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.查看該對象內(nèi)容
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:這段文本是提交備注。(備注與前面留空一行)因為是第一次進(jìn)行commit提交操作,所以沒有父提交信息。
1618190880 +0800:表示時間,一個時間戳。
即:
commit對象的格式很簡單:指明了該時間點項目快照的頂層樹對象、作者/提交者信息(從 Git 設(shè)置的user.name和user.email中獲得),以及當(dāng)前時間戳、留空一行,最后是提交注釋。
提示:
git commit-tree命令不但生成了提交對象,而且會將對應(yīng)的快照(樹對象)提交到本地庫中。
(2)創(chuàng)建第二個commit對象
根據(jù)第二個tree對象和第一個commit對象,來創(chuàng)建第二個commit對象。
通過-p選項指定父提交對象。
# 1.創(chuàng)建第二個commit對象
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
$ echo 'second commit' | git commit-tree 163b45f0a09 -p 3ceba95d3cd9cc
60e1c209e9de87314ec47cf28e61de8df5362fe6
# 2.查看該對象內(nèi)容
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
提交對象的格式很簡單:
它先指定一個頂層樹對象,代表當(dāng)前項目快照;
然后是可能存在的父提交;
之后是作者/提交者信息(依據(jù)你的
user.name和user.email配置來設(shè)定,外加一個時間戳);留空一行,最后是提交注釋。
第三個commit提交,同上,這里就不演示了。
3、本地庫中對象之間的關(guān)系
我們可以查看一下此時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對象。
他們之間的關(guān)系如下圖:

4、總結(jié)
-
提交是我們經(jīng)常使用的Git動作,每次提交操作都指向一個樹對象,同時會產(chǎn)生一個
commit對象。即:一個
commit對象包含了一個tree對象,這個tree對象記錄了在那個時間點,項目包含了什么文件夾和什么文件。 一個提交對象可以有一個或者多個父提交。
每次
commit操作都會基于當(dāng)前索引文件index新建tree對象。那么當(dāng)前索引文件,是在上次提交的基礎(chǔ)上更新來的,所以每次提交產(chǎn)生的commit對象,與其他的commit對象,都有前后關(guān)系或者稱為父子關(guān)系。-
對于我們來說,不需要直接訪問
blob對象和tree對象,我們直接訪問commit對象就可以了。即:
commit對象對應(yīng)的tree對象下面,又包含了小的tree對象和blob對象,子的tree對象一層層展開,最后葉子節(jié)點就是一個個blob對象,也就是一個個文件。
到這里,我們就能夠清楚的了解,什么叫一個Git版本。
tree對象才是一次項目版本的快照,提交對象是對tree對象的一次封裝。即:
- 項目的快照就是一個樹對象。
- 項目的版本就是一個提交對象。
而且Git的每一個版本,存儲的不是增量,而存儲的是當(dāng)前項目的快照。同時
objects目錄中相當(dāng)于存放了項目的所有歷史記錄,回滾就相當(dāng)?shù)姆奖懔耍业綄?yīng)的commit對象的hash就可以了。
5、練習(xí)
請問下圖中包含多少個tree對象和blob對象?

一共包含兩個
tree對象,一個blob對象,一個commit對象。
說明:
- 一個
commit對象一定對應(yīng)一個tree對象(這個tree對象應(yīng)該是一個完整項目倉庫的快照) - doc目錄下有一個blob對象,也就是redme文件。
6、本文用到的命令總結(jié)
Git底層命令:
git commit-tree:生成一個commit對象。git cat-file -t 鍵:查看Git對象的類型。git cat-file -p 鍵:查看Git對象的內(nèi)容。
參考: