原文: http://rypress.com/tutorials/git/plumbing
本文详细介绍GIT Plumbing--更加底层的git命令,你将会对git在内部是如何管理和呈现一个项目repo有一个深入的理解。
除非你想通读Git源代码,你可能永远没有必要使用下面的命令。但是通过手工的操作一个repo将会让你对于GIT如何保存数据的概念细节有个深入理解,你也将对于git是如何工作的有更好的理解。
我们首先来检阅Git的object database,然后我们使用git的低级命令手工创建和commit一个snapshot
Examine Commit Details
首先我们通过git cat-file plumbing command来查看最近的一个commit:
git cat-file commit HEAD
commit参数告诉git我们需要查看一个commit对象。正如我们所知,HEAD指向最近的commit.这将输出下面的信息:
tree 552acd444696ccb1c3afe68a55ae8b20ece2b0e6 parent 6a1d380780a83ef5f49523777c5e8d801b7b9ba2 author Ryan <[email protected]> 1326496982 -0600 committer Ryan <[email protected]> 1326496982 -0600 Add .gitignore file
这是代表一个commit的完整信息:一个tree,一个parent,用户数据和一个commit message.用户信息和commit消息是非常容易理解的,但我们从来没有见过tree或者parent.
一个tree object是git对于一个"snapshot"的代表。他们保存了一个目录在特定时刻的状态,该object没有任何关于时间或者作者的信息。为了将tree和项目一贯的历史信息关联起来,GIT将每一个tree对象包装在一个commit对象中,并且指定一个parent,而这个parent实际上就是另外一个commit.通过遍历每一个commit的parent,你就可以遍历完项目的整个历史。
注意每一个commit refers to one and only one tree object,也就是说commit和tree是一一对应的。从git cat-file输出的内容看,我们可以使用SHA checksum来代表那个tree.这个SHA CHECKSUM对于GIT内部每一个变量都是适用的。
Examine a Tree
下面我们使用git cat-file命令来检阅一个TREE对象。注意将相关的id更新为你的tree的id:
git cat-file tree 552acd4
不幸的是上述命令输出的是binary数据,无法阅读。你可以通过使用下面的git ls-tree命令来输出可阅读的内容。
git ls-tree 552acd4
该命令将输出目录的列表:
100644 blob 99ed0d431c5a19f147da3c4cb8421b5566600449 .gitignore 040000 tree ab4947cb27ef8731f7a54660655afaedaf45444d about 100644 blob cefb5a651557e135666af4c07c7f2ab4b8124bd7 blue.html 100644 blob cb01ae23932fd9704fdc5e077bc3c1184e1af6b9 green.html 100644 blob e993e5fa85a436b2bb05b6a8018e81f8e8864a24 index.html 100644 blob 2a6deedee35cc59a83b1d978b0b8b7963e8298e9 news-1.html 100644 blob 0171687fc1b23aa56c24c54168cdebaefecf7d71 news-2.html ...
通过检查上面命令的输出内容,我们可以假定"blobs"代表了我们repo里面的文件,而trees代表了repo里面的folders。继续通过git ls-tree检阅about tree,我们就可以看到是不是我们的假定是正确的了。
所以,blob对象实际上就是git保存我们文件内容的对象,可以简单理解为文件,tree对象组合了blob和其他的tree对象形成了目录列表,也就是说tree可以简单理解为目录。这些对象就是git最终形成我们在git中常用命令所操作的唯一对象。commit,tree,blob之间的关系可以用下面的图形象展示:
Examine a Blob
我们来看看和blue.html文件相对应的blob:
git cat-file blob cefb5a6
这会展示blue.html文件的整个内容,这也印证了blob本身就是存数据文件,blob本身是纯粹的content,它本身甚至没有任何关于文件名称的信息。也就是说文件名blue.html是保存在包含blob的tree对象中,而不是在blob对象中。
你可能知道SHA-1 checksum确保一个对象的内容永远不会在Git不知情的情况下被篡改。checksum的原理是通过使用对象内容来计算一个唯一的字符序列。这不仅作为一个id,而且它保证一个对象永远不会悄无声息地被修改(而git竟然不知情).当我们来谈到blob对象时,这又有另外一个好处。既然两个具有相同内容的blob永远具有相同的checksum id,那么git可以跨tree来共享一个blob对象。比如我们的blue.html文件自从被创建后就没有被修改,那么我们的repo将只有一个相关联的blob,而所有后续的tree对象都将引用它。通过不去创建重复的blob,Git可以大大降低repo的尺寸。有这个理念作为基础,我们可以修正git的对象图如下:
然而,只要你更改文件的任何一行,Git都必需创建一个新的blob对象来反映这个修改,因为内容变更,SHA-1 checksum就将变更。当然,GIT也有一些增量修改的机制来保证这个尺寸增加不是很大的问题。
Examine a Tag
第四个也是最后一个git object是tag对象