本文首发于公众号“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
命令中的第二个参数---父提交对象,每一个提交对象都保存了上一个父提交对象的引用,这样就串起来一个提交历史记录了。
欢迎关注个人公众号查看更多精彩文章!
复制代码