Git基础对象模型介绍

阿左的小站 2011-04-23

Git基础对象模型介绍

[email protected]

本文翻译自http://book.git-scm.com/1_the_git_object_model.html,但不是全文翻译,仅供学习参考,不贴切之处敬请指正。

Git是什么?

Git是一个快速、分布式的版本控制系统。

Git的对象模型

什么是SHA?

用来代表项目历史的所有信息都存储在一个文件中,这个文件名由40个字符构成,表示所谓的“对象“,看起来象:

引用
49b1775c245cbf030f52ce0c50d3758617e02395

在Git中,象这样的40个字符组成的字符串随处可见,它是由对象的内容做SHA1哈希计算得到的。所谓的SHA1哈希是一个加密的哈希函数。这样做的意义是实际上不可能找到两个不同的对象拥有相同的SHA1值(对象名)。这样做有一系列的好处,比如:

  • Git可以快速的仅仅通过对象名称决定两个对象是否相同
  • 由于对象名称在每一个库(repository)中都由相同的方式计算得到,相同的内容存储到不同的库中将总被存储到相同的名称下
  • Git可以在读取对象时通过检查对象的内容SHA1之后是否是相同的名字来检测错误(这样做的原因是由于相同的内容经过SHA1计算之后总是具有相同的SHA1值)

什么是对象?

每个对象有三个属性:类型、尺寸和内容。

尺寸就是对象的大小,内容基于对象的类型。在Git中有四种类型,分别是"blob","tree","commit",and"tag"。

  • blob:用来存储文件数据,就是一个通常的文件。
  • tree:看起来象一个目录结构,它引用了一串其他的tree或者blob(就像文件和子目录一样)。
  • commit:指向一个单独的tree,标志着一个项目在一个特定的时间点看起来是什么样子。它包含了那一时间点的元信息,比如时间戳、作者、自从上次提交以来所做的改变、指向前一次提交的引用,等等。
  • tag:是用特定的方法标识特定的提交。它通常用来标记特定的commit作为特定的release,或者这条主线上的其他的什么东西。
几乎所有的Git都建立在管理操纵这些简单的结构之上,即它是建立在机器文件系统之上的一种自己的小型文件系统。
  • Blob对象(BlobObject)Blob对象通常存储文件的内容。可以使用命令
gitshow来查看人和blob对象的内容。比如:
引用
$ git show ced3dd435d0468

commitced3dd435d04684ad44232709bd35841240364c6

Author:GuibinZhang<[email protected]>

Date:WedApr2017:31:312011+0800

Fixpublishwithnullproperties

diff--gita/libs/lib.service.securities/src/main/scala/com/aiotrade/lib/service/securities/cndbf/LevelIIDataPublisher.scala

index535bc85..2f1650e100644

---a/libs/lib.service.securities/src/main/scala/com/aiotrade/lib/service/securities/cndbf/LevelIIDataPublisher.scala

+++b/libs/lib.service.securities/src/main/scala/com/aiotrade/lib/service/securities/cndbf/LevelIIDataPublisher.scala

@@-166,7+166,8@@objectLevelIIDataPublisherextendsReactor{

if(rountingKey.isDefined&&secId.isDefined){

valtopic=rountingKey.get+secId.get+".SZ"

-publisher.publish(exchange,topic,null,recordObjs)

+publisher.publish(exchange,topic,props,recordObjs)

blob对象实际上就是一块二进制数据。它不会引用任何其他东西,也没有人和其他属性,甚至都没有文件名。

既然blob对象完全由其数据决定,如果两个文件在同一个目录树下(或者在多个不同版本的库中),那么他们将会共享相同的blob对象。blob对象完全独立于它在目录树中的位置,即便是对文件重命名也不会改变与此文件相关联的blob对象的内容。

Tree对象(TreeObject)Tree对象比较简单,它有很多指针,指向其他blob和tree,它代表目录或者子目录的内容。git tree命令能够用来检查tree对象的内容,或者使用git ls-tree可以查看更多细节。如下面的例子
引用
$ git ls-tree 49b1775c245cbf030f52ce0c50d3758617e02395

040000tree7e814915c9880cb367895118333f2cd4e600855bapplication

040000tree561d4f6709e0b27943d5f0d650f9986e74673e69branding

100644blobaf0ae6a9fc24e6978287d47eda2727c1c664f524pom.xml

就像你所看到的,tree对象包含一系列入口,每个入口保护模式(如040000,100644),对象类型(tree,blob),SHA1名称(7e814915...,561d4f67...,af0ae6a9fc...),和名字(application,branding,pom.xml)。这些内容都是tree对象49b1775c245cbf030f52ce0c50d3758617e02395...的内容,内容列出的顺序按照名称排序。这些内容就是一个单独文件夹的内容。

能够被tree对象引用的对象可以是:blob对象-代表文件的内容,另外的tree对象-代表子目录的内容。既然tree对象和blob对象和其他对象一样,都是由其内容的SHA1hash值决定,因此两个tree对象当且仅当他们的内容(递归的包含其子目录的内容)相同时才具有相同的SHA1值。这个特性使得git能够快速决定两个相关的tree对象的差异,因为在判断两个tree是否相同时可以忽略tree对象下面的相同名字的对象。

注意,具有644和755权限的文件,git实际上只对可执行权限位感兴趣。

Commit对象(CommitObject)Commit对象链接一个Tree的物理状态和其描述。这个描述描述了我们如何提交到这个commit,怎么提交的,相当于一些注释。

你可以用在gitshow命令和gitlog命令中使用--pretty=raw选项查看你所感兴趣的提交(commit)。

引用
$ git show -s --pretty=raw c1e78911e06

commitc1e78911e066983c797129b196f60cef256c3a3a

tree1afa3f0f14c1fffed0fbf3cc05507034c61cfeb4

parentffbeb1730537cc139bee4358010afc9953cb8615

authorGuibinZhang<[email protected]>1303277354+0800

committerGuibinZhang<[email protected]>1303277354+0800

Fixpublishtowrongtopicbug

正如你所见到的,一个commit由以下几个元素组成:

1.Tree。即Tree对象的SHA1名字,代表在特定时间点某个目录的内容。

2.Parent。在此次提交之前的一个或几个commit的名字。上面的例子中,只有一个parent,但是Mergecommit可能就有多个parent。比如

引用
$ git show -s  --pretty=raw 49b1775c24

commit49b1775c245cbf030f52ce0c50d3758617e02395

tree89de7605c4ec6677b3960acd7621cdb70371362b

parent10096820c833d42b53ed40886bb91e37f7e2607f

parentb0cbbf20457bc7a755391b93c0f6278cb0b47b2e

authorGuibinZhang<[email protected]>1303449511+0800

committerGuibinZhang<[email protected]>1303449511+0800

Mergebranch'master'of192.168.80.141:/home/guibin/Project/faster/faster

如果一个commit没有parent,那么这个commit就一定是rootcommit,代表当这个项目初始化时的状态。每个项目都至少有一个root。一个项目也可以有多个root,但这不常见,也不必要。

3.Author。对此次commit负责的作者及其提交时间。

4.Committer。谁实际执行了此次提交操作及其提交时间。committer可能和author不一样,比如作者写了些代码,发送给提交者提交。

5.Comment。注释。

注意:一个commit事实上并没有记录这次提交做了什么内容的改变,所有的改变都根据这次commit所引用的对象的内容和其parent计算得到,尤其是git并不试图去显示的记录rename这些操作,虽然它能够根据相同的文件内容和不同的文件路径计算出rename。commit对象通常由gitcommit命令创建,提交时,此次提交的parent就是提交时刻的HEAD,并且HEAD的tree提取自当前存储在index中的内容。

Tag对象(TagObject)Tag对象包含了对象名称,对象类型,tag名称,打tag的人(tagger)和一条注释。可以使用gittag命令去创建或者验证tag,细节请参考gittag--help

Git与SVN的区别

非常重要的一点是Git与多数你所熟悉的SCM系统都不同。Subversion,CVS,Perforce,Mercurial都使用DeltaStoragesystems,即他们都存储一个commit和另一次commit之间的区别,而Git却不是这样做的,它存储在项目中所有文件在这种树型结构中的快照。在使用Git时这是一个非常重要的概念。

相关推荐

好脑筋不如烂笔头 / 0评论 2016-11-22