1e92 new.txt
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
最终,整个树对象的结构如下图:
树对象解决了文件名的问题,而且,由于我们是分阶段提交树对象的,树对象可以看做是开发阶段源代码目录树的一次次快照,因此我们可以是用树对象作为源代码版本管理。但是,这里仍然有问题需要解决,即我们需要记住每个树对象的hash值,才能找到个阶段的源代码文件目录树。在源代码版本控制中,我们还需要知道谁提交了代码、什么时候提交的、提交的说明信息等,接下来的提交对象就是为了解决这个问题的。
提交对象
提交对象是用来保存提交的作者、时间、说明这些信息的,可以使用git commit-tree
来将提交对象写入到Git文件系统中:
$ echo 'first commit' | git commit-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
db1d6f137952f2b24e3c85724ebd7528587a067a
上面commit-tree
除了要指定提交的树对象,也要提供提交说明,至于提交的作者和时间,则是根据环境变量自动生成,并不需要指定。这里需要提醒一点的是,读者在测试时,得到的提交对象hash值一般和这里不一样,这是因为提交的作者和时间是因人而异的。
提交对象的查看,也是使用git cat-file
:
$ git cat-file -p db1d6f137952f2b24e3c85724ebd7528587a067a
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author jingsam <jing-sam@qq.com> 1528022503 +0800
committer jingsam <jing-sam@qq.com> 1528022503 +0800
first commit
上面是属于首次提交,那么接下来的提交还需要指定使用-p
指定父提交对象,这样代码版本才能成为一条时间线:
$ echo 'second commit' | git commit-tree 0155eb4229851634a0f03eb265b69f5a2d56f341 -p db1d6f137952f2b24e3c85724ebd7528587a067a
d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c
使用git cat-file
查看一下新的提交对象,可以看到相比于第一次提交,多了parent
部分:
$ git cat-file -p d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c
tree 0155eb4229851634a0f03eb265b69f5a2d56f341
parent db1d6f137952f2b24e3c85724ebd7528587a067a
author jingsam <jing-sam@qq.com> 1528022722 +0800
committer jingsam <jing-sam@qq.com> 1528022722 +0800
second commit
最后,我们再将树对象3c4e9c
提交:
$ echo 'third commit' | git commit-tree 3c4e9cd789d88d8d89c1073707c3585e41b0e614 -p d4d2c6cffb408d978cb6f1eb6cfc70e977378a5c
3ac728ac62f0a7b5ac201fd3ed1f69165df8be31
使用git log
可以查看整个提交历史:
-
2 files changed, 2 insertions(+), 1 deletion(-)
commit db1d6f137952f2b24e3c85724ebd7528587a067a
Author: jingsam <jing-sam@qq.com>
Date: Sun Jun 3 18:41:43 2018 +0800
first commit
test.txt | 1 +
1 file changed, 1 insertion(+)
最终的提交对象的结构如下图:
总结
Git中的数据对象解决了数据存储的问题,树对象解决了文件名存储问题,提交对象解决了提交信息的存储问题。从Git设计中可以看出,Linus对一个源代码版本控制系统做了很好的抽象和解耦,每种对象解决的问题都很明确,相比于使用一种数据结构,无疑更灵活和更易维护。每种Git对象都有一个hash值,这个值是怎么计算出来的?Git的各种对象是如何存储的?这些问题将在下一篇文章中讲解。