深入理解Git原理(1)Git object

Git是现在最流行的分布式版本控制工具,本系列文章将带大家了解Git的内部工作原理。如果你还没有使用过Git,可以参考Git新手教程(1) 

key-value数据库

使用git时相信大家经常会看到一串十六进制数字,其实这一串数字是某个对象的SHA1值。关于密码学中的哈希函数可以参考认识区块链(1)——哈希算法 | 雅乐网

git提供了底层的命令 git hash-object ,可以用来操作git中的对象

$ echo "yalewoo.com" | git hash-object --stdin
95a7073153bacf84c44b1c79b4b6e6a863e25dca

上面命令中的–stdin表示从输入流读数据,作用是查看”yalewoo.com”的SHA1值。注意git自身会对对象的内容进行压缩存储,因此这里的SHA1是在压缩后的消息上计算的。

如果带有-w参数,表示将这个object写入git的数据库

$ git init
Initialized empty Git repository in D:/code/learngit/.git/

$ echo "yalewoo.com" | git hash-object --stdin -w
95a7073153bacf84c44b1c79b4b6e6a863e25dca

我们可以在.git/objects/目录下看到刚刚加入的object

使用 git cat-file命令可以查看object,-p表示打印内容,-t可以查看类型

$ git cat-file 95a7073153bacf84c44b1c79b4b6e6a863e25dca -t
blob
$ git cat-file 95a7073153bacf84c44b1c79b4b6e6a863e25dca -p
yalewoo.com

可以看到类型是blob,这个blob的内容就是刚刚加入时实际的内容”yalewoo.com”。

Commit

我们先创建一个blog.txt文件,用来存放优秀博客列表

$ echo "yalewoo.com" > blogs.txt
$ git hash-object blogs.txt
95a7073153bacf84c44b1c79b4b6e6a863e25dca

再创建一个目录 details 存放每个博客的详细信息,里面有两个文件,readme和yalewoo.txt。注意这里yalewoo.com.txt里面的内容和blogs.txt的内容是一样的。

$ mkdir details
$ echo "details readme" > details/readme.txt
$ echo "yalewoo.com" > details/yalewoo.com.txt

然后我们来提交

$ git add *
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   blogs.txt
        new file:   details/readme.txt
        new file:   details/yalewoo.com.txt

$ git commit -m "first commit"
[master (root-commit) 606b6c3] first commit
 3 files changed, 3 insertions(+)
 create mode 100644 blogs.txt
 create mode 100644 details/readme.txt
 create mode 100644 details/yalewoo.com.txt

可以看到本次提交的commit的SHA1是606b6c3…

$ git cat-file -t 606b6c3
commit

$ git cat-file -p 606b6c3
tree d096dd512f1c699f99310e4fb2d05f34b76f2468
author yalewoo <chongruyuntian@163.com> 1568515063 +0800
committer yalewoo <chongruyuntian@163.com> 1568515063 +0800

first commit

打印本次commit的内容,可以发现,git里的一个commit只是记录了一些文本。其中tree指向了另一个git对象,另外还包含了提交作者,提交者和提交注释。

$ git cat-file -t d096dd512f1c699f99310e4fb2d05f34b76f2468
tree

$ git cat-file -p d096dd512f1c699f99310e4fb2d05f34b76f2468
100644 blob 95a7073153bacf84c44b1c79b4b6e6a863e25dca    blogs.txt
040000 tree 2c6c24f3530f2d4be7f8a1290b930a8f3e11b7dc    details

tree对象类似文件系统中的目录,可以包含其他tree和blob。这个tree里包含了blogs.txt这个blob对象和details目录。

你应该还记得,”yalewoo.com”的SHA1就是这里的95a7073153bacf84c44b1c79b4b6e6a863e25dca, 这个对象记录的就是”yalewoo.com”这个字符串。而文件名blogs.txt是记录在tree对象里面的。

类似的,我们可以看一下details对应的tree对象,

$ git cat-file -p 2c6c24f3530f2d4be7f8a1290b930a8f3e11b7dc
100644 blob 3fd224609fd7dd3e97b5e8ec134ba84b7052efeb    readme.txt
100644 blob 95a7073153bacf84c44b1c79b4b6e6a863e25dca    yalewoo.com.txt

yalewoo.com.txt对应的blob仍然是那个95a7073,可以看出文件内容相同的文件在git里只会存放一份!

你可以在.git/objects/目录里看到所有的object,然后使用git cat-file查看他们。

现在所有的object是这样组织的

第二次commit

我们改一下blogs.txt文件,在最下面加入一行: wordpress.com

$ cat blogs.txt
yalewoo.com
wordpress.com

然后再次commit

$ git add blogs.txt

$ git commit -m "change blogs.txt"
[master c428c2c] change blogs.txt
 1 file changed, 1 insertion(+)

可以看到一个新的commit诞生了。我们可以使用上面的方法查看这次commit。

$ git cat-file c428c2c -p
tree 8252d83070251e9c6c74ea13990ef8c787658e6e
parent 606b6c3d7e55733783be97b7fc2b929eaa3b790c
author yalewoo <chongruyuntian@163.com> 1568516737 +0800
committer yalewoo <chongruyuntian@163.com> 1568516737 +0800

change blogs.txt

这次commit和第一次不同的是,他有一个parent,指向的正是第一次提交的commit.

details目录下的内容没有改动,所以对应的tree结点仍然是原来的。

Git object

git中的object一共有4种类型,除了上面的commit, tree和blob,还有annotated tag,大家可以自行了解。

 

谢谢观看~下一次我们讲git中的分支。

如果文章对你有帮助,欢迎点赞或打赏(金额不限)。你的打赏将全部用于支付网站服务器费用和提高网站文章质量,谢谢支持。

版权声明:

本文由 原创,商业转载请联系作者获得授权。
非商业转载请注明作者 雅乐网 ,并附带本文链接:
https://www.yalewoo.com/master_git_1_object_database.html

上一篇:

下一篇:

我要评论

验证码*: 7 + 8 =