提交對象
一般我們平時有了需要提交的文件,都是2步走:add,然后commit
add操作
第一步:添加文件
//添加文件到暫存區(qū)
git add test.txt
這一步Git做了2件事:
- 將文件的內容用之前數據對象一節(jié)中提到的方法創(chuàng)建數據對象并保存到Git數據庫中(計算SHA-1值拴签、生成文件目錄、寫入壓縮后的內容)
- 更新 Index文件洗显,也就是我們平時說的 暫存區(qū)棱貌,增加或是更新指向
text.txt
文件的索引,等待后續(xù)的第二步操作
commit:創(chuàng)建提交記錄
//提交到Git本地倉庫
git commit -m "XXX"
這個步驟是創(chuàng)建了一個提交對象精续,提交對象里面就記錄了提交的時間坝锰、作者、以及提交的原因等信息重付。
上述 git commit
命令做了以下幾件事:
首先所有具體文件的數據顷级,已經在
add
操作時用數據對象記錄在Git數據庫中,并且所有文件的索引都保存在暫存區(qū)中确垫,所以commit
操作就不用再創(chuàng)建數據對象了如果暫存區(qū)中存在目錄關系弓颈,就會先創(chuàng)建樹對象來記錄文件目錄關系,這樣文件數據和目錄關系都有了記錄
然后會再創(chuàng)建一個樹對象删掀,代表當前項目快照翔冀,這個樹對象里面包含的就是上述信息,也就是所有要保存記錄的數據
然后用這個樹對象爬迟,配置中的user.name和email橘蜜,以及當前的時間戳和
-m
參數后面的內容生成提交對象
我們可以用 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
里面確實是有一個樹的索引跌捆,這個樹對象就是前面創(chuàng)建的頂層樹對象。
此時象颖,有個疑問:已經用暫存區(qū)的內容創(chuàng)建了提交對象佩厚,那暫存區(qū)的內容還在嗎?
答案是:仍然存在
Git在執(zhí)行commit命令時會根據暫存區(qū)創(chuàng)建樹對象说订,暫存區(qū)沒變抄瓦,創(chuàng)建的樹對象就是同一個,也就是不會重復創(chuàng)建陶冷。
最后我們看看commit對象的一個示意圖
commit歷史記錄
上面我們用 git commit
命令創(chuàng)建了一個commit對象钙姊,實際上底層調用的是 commit-tree
命令。
commit-tree
命令里面需要確定2個參數:一個是需要指定一個樹對象埂伦,第二個需要指定上一個提交對象(作為父提交對象)
// -p 后面的就是上一個提交對象
echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
下面我們來模擬連續(xù)提交3次
echo 'version 1' > test.txt
git add .
git write-tree
//輸出樹對象SHA-1值
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
//創(chuàng)建第一個提交對象
echo 'first commit' | git commit-tree d8329fc
//輸出提交對象的SHA-1值
xxxxxxxc670d30e9817fd1af481aca92f8d700c2
//然后添加新文件煞额,創(chuàng)建新的樹對象
echo 'version 2' > test.txt
echo 'new file' > new.txt
git add .
git write-tree
//輸出新的樹對象的SHA-1值
0155eb4229851634a0f03eb265b69f5a2d56f341
//接著創(chuàng)建新的提交對象
echo 'second commit' | git commit-tree 0155eb -p 9f17fcc
//輸出新提交對象的SHA-1值
xxxxxxx9f57c7a0632084e2c9eb38e3584180e23
//先把之前的第一版的test.txt讀入暫存區(qū)作為子樹
git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
git write-tree
//輸出新樹的SHA-1值
3c4e9cd789d88d8d89c1073707c3585e41b0e614
//接著創(chuàng)建新的提交對象
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
命令中的第二個參數---父提交對象栅螟,每個提交對象都保存了上一個父提交對象的引用,這樣就串起來一個提交歷史記錄了篱竭。