本文首發於公衆號「AntDream」,歡迎微信搜索「AntDream」或掃描文章底部二維碼關注,和我一塊兒天天進步一點點git
通常咱們平時有了須要提交的文件,都是2步走:add,而後commit數據庫
第一步:添加文件bash
//添加文件到暫存區
git add test.txt
複製代碼
這一步Git作了2件事:微信
text.txt
文件的索引,等待後續的第二步操做//提交到Git本地倉庫
git commit -m "XXX"
複製代碼
這個步驟是建立了一個提交對象,提交對象裏面就記錄了提交的時間、做者、以及提交的緣由等信息。ui
上述 git commit
命令作了如下幾件事:spa
首先全部具體文件的數據,已經在 add
操做時用數據對象記錄在Git數據庫中,而且全部文件的索引都保存在暫存區中,因此 commit
操做就不用再建立數據對象了code
若是暫存區中存在目錄關係,就會先建立樹對象來記錄文件目錄關係,這樣文件數據和目錄關係都有了記錄cdn
而後會再建立一個樹對象,表明當前項目快照,這個樹對象裏面包含的就是上述信息,也就是全部要保存記錄的數據對象
而後用這個樹對象,配置中的user.name和email,以及當前的時間戳和 -m
參數後面的內容生成提交對象blog
咱們能夠用 git log
命令,查看提交的歷史記錄,就能拿到 commit
的 SHA-1值(也就是咱們平時說的commit id)
而後用 git cat-file
命令就能查看這個提交裏面的信息
git cat-file -p xxxxxxx0ab25ce7b1c6019c411e760a17205d7b0
//輸出
tree 9bfb857f532d280ecd7704beb40a2ea4ba332f5a
author xxx <xxx@qq.com> 1561964726 +0800
committer xxx <xxx@qq.com> 1561964726 +0800
first commit
複製代碼
能夠看到,commit
裏面確實是有一個樹的索引,這個樹對象就是前面建立的頂層樹對象。
此時,有個疑問:已經用暫存區的內容建立了提交對象,那暫存區的內容還在嗎?
答案是:仍然存在
Git在執行commit命令時會根據暫存區建立樹對象,暫存區沒變,建立的樹對象就是同一個,也就是不會重複建立。
最後咱們看看commit對象的一個示意圖
上面咱們用 git commit
命令建立了一個commit對象,實際上底層調用的是 commit-tree
命令。
commit-tree
命令裏面須要肯定2個參數:一個是須要指定一個樹對象,第二個須要指定上一個提交對象(做爲父提交對象)
// -p 後面的就是上一個提交對象
echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
複製代碼
下面咱們來模擬連續提交3次
echo 'version 1' > test.txt
git add .
git write-tree
//輸出樹對象SHA-1值
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
//建立第一個提交對象
echo 'first commit' | git commit-tree d8329fc
//輸出提交對象的SHA-1值
xxxxxxxc670d30e9817fd1af481aca92f8d700c2
//而後添加新文件,建立新的樹對象
echo 'version 2' > test.txt
echo 'new file' > new.txt
git add .
git write-tree
//輸出新的樹對象的SHA-1值
0155eb4229851634a0f03eb265b69f5a2d56f341
//接着建立新的提交對象
echo 'second commit' | git commit-tree 0155eb -p 9f17fcc
//輸出新提交對象的SHA-1值
xxxxxxx9f57c7a0632084e2c9eb38e3584180e23
//先把以前的初版的test.txt讀入暫存區做爲子樹
git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
git write-tree
//輸出新樹的SHA-1值
3c4e9cd789d88d8d89c1073707c3585e41b0e614
//接着建立新的提交對象
echo 'third commit' | git commit-tree 3c4e9c -p 8565637
//輸出第3次提交的SHA-1值
xxxxxxx747d9e83f3c05d10cbc68f876a8abf0d1
複製代碼
以上咱們用 git的底層命令模擬了實際的三次 git commit操做,咱們來看一下成果:
//--stat參數可讓git顯示每一次提交改動的文件信息
git log --stat f32da7d
複製代碼
經過以上的步驟咱們就從底層知道了咱們每次 git add
和 git commit
的過程,同時咱們知道,每一次咱們 commit
的時候,都會記錄上一個 commit
的 SHA-1值,這樣一個個的 commit
就串起了咱們的提交記錄。
那麼問題來了,Git是怎麼知道新 commit
對象的上一個 commit
對象的呢?實際上就是上面commit-tree
命令中的第二個參數---父提交對象,每一個提交對象都保存了上一個父提交對象的引用,這樣就串起來一個提交歷史記錄了。
歡迎關注個人公衆號查看更多精彩文章!
複製代碼