看日记学git

《看日记学git》之十一

《看日记学git》系列

《看日记学git》之序 《看日记学git》之一

《看日记学git》之二 《看日记学git》之三

《看日记学git》之四 《看日记学git》之五

《看日记学git》之六 《看日记学git》之七

《看日记学git》之八 《看日记学git》之九(总结)

《看日记学git》之十

===

接下来的内容是以“之一~之十”的内容为基础的,内容将围绕对象数据库和索引文件展开,这是为了更好的理解git的工作机制和体系结构。

系列之十一将讲解“对象数据库(object database)”

1

为了讲清楚object database这个概念,我们先建立一个git仓库:

$ mkdir test-project

$ cd test-project

$ git init

$ echo ‘Hi,rocrocket’>file.txt

$ git add .

$ git commit -a -m “initial commit” //此处的-m选项表示“后面的参数是本次提交的历史记录”

$ echo ‘Hi,rocrocket!’>file.txt

$ git commit -a -m “add emphasis”

$ git log //使用log命令查看一下

Created commit d85012f: add emphasis
1 files changed, 1 insertions(+), 1 deletions(-)
[rocrocket@wupengchong test-project]$ git log
commit d85012f4d17a774c7286f4d7d022f022d3b90073
Author: rocrocket <wupengchong@gmail.com>
Date:   Fri Sep 26 10:58:15 2008 +0800

add emphasis

commit 241e0a4d2a5644f92737b7fba8b9eb19dcb0c345
Author: rocrocket <wupengchong@gmail.com>
Date:   Fri Sep 26 10:57:13 2008 +0800

initial commit

你可曾想过到底这些跟在commit字符串后面的一大长串(共40位)十六进制数字是干什么用的??

通过前十期的学习,我们知道这40位十六进制数是用来“标识一次commit”的名称。其实,这40位十六进制数是一个SHA1哈希数(Secure Hash Algorithm),它可以保证每次commit生成的名称都是唯一的且可以永远有效的。

2

执行下面命令:

[rocrocket@wupengchong test-project]$ git cat-file -t 241e //cat-file命令中-t选项表示列出相应ID的对象类型;241e是刚才commit后得出的SHA1码
commit //可以看到此ID对应的对象类型为一次commit
[rocrocket@wupengchong test-project]$ git cat-file commit 241e //此处的commit表示要查询的是一个对象类型为commit的对象,后面给出此对象的ID

tree 9a327d5e3aa818b98ddaa7b5b369f5deb47dc9f6
author rocrocket <wupengchong@gmail.com> 1222397833 +0800
committer rocrocket <wupengchong@gmail.com> 1222397833 +0800

initial commit

你应该可以注意到命令输出结果中包含了tree,tree的ID表示了一个BLOB对象(二进制对象),此对象对应着一个文件或另一个tree。你可以使用ls-tree命令来查询关于这个tree的更详细信息:

[rocrocket@wupengchong test-project]$ git ls-tree 9a327

100644 blob 7d4e0fa616551318405e8309817bcfecb7224cff file.txt

我们可以看到9a327这棵树上包括了一个file.txt文件,其ID为7d4e0f

[rocrocket@wupengchong test-project]$ git cat-file -t 7d4e0f
blob
[rocrocket@wupengchong test-project]$ git cat-file blob 7d4e0f
Hi,rocrocket

可以看到7d4e0f对应的对象的类型是blob,而其内容就是“Hi,rocrocket”

3

所有的对象信息都存储在.git/objects/目录下,使用find命令查看一下:

./objects
./objects/pack
./objects/24
./objects/24/1e0a4d2a5644f92737b7fba8b9eb19dcb0c345
./objects/fb
./objects/fb/4ec0f35525992eda56021f161f85f637837404
./objects/d8
./objects/d8/5012f4d17a774c7286f4d7d022f022d3b90073
./objects/7d
./objects/7d/4e0fa616551318405e8309817bcfecb7224cff
./objects/9a
./objects/9a/327d5e3aa818b98ddaa7b5b369f5deb47dc9f6
./objects/info
./objects/60
./objects/60/be00dabc677b196938758ef41457cc17b77b70

这些对象都是被压缩过的,其类型可以是blob,tree,commit或tag。其中包括了对象长度、对象类型和对象的内容。

4

在.git目录下的HEAD文件比较特殊,查看.git/HEAD文件:

[rocrocket@wupengchong .git]$ cat HEAD
ref: refs/heads/master
[rocrocket@wupengchong .git]$ cd ..
[rocrocket@wupengchong test-project]$ git branch
* master

可以看到HEAD文件指示出当前所在的分支名称是master。其实更引起我们兴趣的是HEAD文件中所指示的这个路径“refs/heads/master”,我们随着HEAD的思路走下去:

[rocrocket@wupengchong test-project]$ cat .git/refs/heads/master
d85012f4d17a774c7286f4d7d022f022d3b90073

这个文件的内容给出了一个对象ID,继续寻根溯源:

[rocrocket@wupengchong test-project]$ git cat-file -t d850
commit
[rocrocket@wupengchong test-project]$ git cat-file commit d850
tree fb4ec0f35525992eda56021f161f85f637837404
parent 241e0a4d2a5644f92737b7fba8b9eb19dcb0c345
author rocrocket <wupengchong@gmail.com> 1222397895 +0800
committer rocrocket <wupengchong@gmail.com> 1222397895 +0800

add emphasis

谜底揭开了。HEAD所指向的原来是最后一次commit的信息,而且经测试可知parent指的是上一次commit的信息。

5

到目前为止,我们应该已经知道了对象数据库是如何管理历史记录的了:

  • commit对象会指向一个tree对象,即在历史记录中当前结点的tree目录的镜像;也会指向父母(parent)commit,这是为了和之前的commit建立关联。
  • tree对象用于显示一个目录的状态,tree对象中包含了blob对象和子目录对象。
  • blob对象包含的是文件的数据。
  • 每个分支的HEAD会存储在.git/refs/heads中。同时,当前所在分支的头部会存储在.git/HEAD中。

===
如果你对git感兴趣,请继续阅读:

《看日记学git》之十二

《看日记学git》之十三

《看日记学git》之十四

over~

1条评论

发表您的评论

请您放心,您的信息会被严格保密。必填项已标识 *