# 6.1.2 Git基本原理
### 6.1.2 Git基本原理
与CVS或者SVN等一般软件不同,要想掌握Git,必须对其实现原理有深入的理解;否则只能停留在表面的简单操作上,一旦遇到复杂问题就无从下手。
了解Git的基本原理需要从Git仓库的数据结构入手。Git把一个项目所有的版本和历史数据保存在一个Git仓库(Repository)里。仓库通常位于项目根目录下的.git子目录,主要包含两种数据:对象存储(object store)和索引(index)。
#### 对象存储(object store)
对象存储(object store)中的对象共有4种类型:
- Blob - 一个blob对象对应着项目的一个文件的内容(不包括文件名、创建/修改时间等信息)。项目的每个文件的每个不同版本都对应着一个blob对象。
- Tree - 一个tree对象对应着一层目录结构,每个目录项包括文件名、文件对应的blob对象或者另一个tree对象的引用(可以看出,利用blob和tree对象可以实现一个完整的多层次目录结构)。
- Commit - 一个commit对象保存着用户的一次commit数据,包括:作者信息、提交日期和日志,以及一个指向tree对象的引用(注意commit对象并不包括版本之间的diff差异,后详)。
- Tag - 一个tag对象含有对另一个对象(通常是commit对象)的引用,以及一些附加的注释信息,主要供人类阅读。
举例来说,假设一个项目的目录结构如下:
```
.
├── hello.txt
└── sub-dir
└── world.txt
```
同时假设这个项目只进行了一次commit(包含以上两个文件和一个子目录)并且该commit上有一个tag,那么项目对应的Git对象存贮应如下图所示:
![git-object-store](https://box.kancloud.cn/813b7a369239e23774390ec4a386f014_354x453.png)
需要注意的是:我们在前面提到的“对像引用”,如Tree对象代表的目录中每个目录项含有的对blob或者另一个tree对象的引用,commit对象含有的对tree对象的引用,以及tag对象对一个commit对象的引用,不是依赖文件系统的路径来表示的,而是由对象内容得出的SHA1哈希代码,类似`670a245535fe6316eb2316c1103b1a88bb519334`。因此上图可修正如下:
![git-object-store2](https://box.kancloud.cn/814d115737b15510914b47f52e60d98d_400x472.png)
在项目的根目录下执行
```
find .git/objects/
```
可以看到项目的Git仓库中的所有的对象,类似如下:
```
.git/objects/
.git/objects//0d
.git/objects//0d/8ad63a4626b776800bbed61c2dac660c5037e2
.git/objects//1d
.git/objects//1d/5230840c2573394e0ae86f30e01e03062804fc
.git/objects//38
.git/objects//38/8df287b748962a5a1e28a36172fce3240b53e8
.git/objects//4a
.git/objects//4a/3ec58d02c75da1d303d55a08cd172508256525
.git/objects//5a
.git/objects//5a/e514f1ff6a54b6de97db5418038b4b183d8764
.git/objects//67
.git/objects//67/0a245535fe6316eb2316c1103b1a88bb519334
.git/objects//info
.git/objects//pack
```
它们都是以对象内容的SHA1码来命名的。你还可以通过以下命令查看其内容:
```
git cat-file -p 0d8ad63
```
以上`0d8ad63`是`0d8ad63a4626b776800bbed61c2dac660c5037e2`的短前缀——在不引起冲突的情况下可以使用短前缀代替完整的SHA1码。
Git通过对象内容的SHA1哈希码来存贮、引用对象的方式称作**通过内容寻址的存贮(Content-Addressable Storage)**。
现在我们进一步:如果修改了`hellt.txt`的内容并提交一个新的commit,对象存贮如何变化?它变成了这样:
![git-object-store3](https://box.kancloud.cn/32161a7b7dd90234f64f08892f1caf94_544x474.png)
仔细对比一下前后两张图,*Git的奥妙就在这里*:
- `hello.txt`的内容改变后,Git新增了一个blob对象,对应着`hello.txt`的新内容,并且有一个新的SHA1代码。
- 由于`hello.txt`的SHA1代码改变了,因此包含这个blob对象的tree对象也发生了变化(因为要更新对`hello.txt`的引用)。同样地,Git也新增了一个tree对象对应着新内容。同时,`sub-dir`的内容没有变化,因此新的tree对象仍然引用着原来的`sub-dir`对象(而不是拷贝一份)。
- 新的commit对象包含这个新的tree对象的引用,同时指向之前的commit对象——这样就形成了历史版本纪录,并且你随时可以恢复任何一个历史版本!
#### 索引(index)
根对象存贮相比,索引就简单的多:它不过是一个临时文件,用来存贮你对项目做的一些改变,如增加、删除、修改文件或者目录等。一般地,你使用`git add`、`git rm`等命令把你修改过的文件、目录提交到这个索引中去,然后应用`git commit`命令来完成一次提交。
- 前言
- 1 Web概述
- 1.1 什么是Web
- 1.2 超文本和超链接
- 1.3 URL
- 1.4 DNS
- 1.5 HTTP
- 1.5.1 客户端请求
- 1.5.2 服务器应答
- 1.5.3 进一步了解HTTP
- 1.6 HTTPS
- 2 Web浏览器
- 2.1 HTML
- 2.1.1 文档类型声明
- 2.1.2 标签和属性
- 2.1.3 文档结构
- 2.1.4 DOM
- 2.1.5 进一步了解HTML
- 2.2 CSS
- 2.2.1 样式与样式表
- 2.2.2 样式表语法
- 2.2.3 级联样式表
- 2.2.4 进一步了解CSS
- 2.3 JavaScript
- 2.3.1 script标签
- 2.3.2 操纵DOM
- 2.3.3 jQuery
- 2.3.4 进一步了解JavaScript
- 2.4 Ajax
- 2.5 移动设备与响应式Web设计
- 3 Web服务器
- 3.1 方法与资源
- 3.2 状态代码
- 3.3 静态内容与动态内容
- 3.4 编程语言与技术
- 3.4.1 CGI
- 3.4.2 PHP
- 3.4.3 Java
- 3.4.4 Python
- 3.4.5 Ruby
- 3.4.6 Node.js
- 3.5 RESTful Web API
- 3.6 服务器架构
- 3.7 Web缓存
- 3.8 服务器推送
- 4 数据库
- 4.1 关系型数据库
- 4.2 NoSQL数据库
- 5 Web服务器的其他组件
- 5.1 Cron
- 5.2 消息队列
- 5.3 邮件服务器
- 6 开发工具与技术
- 6.1 Git
- 6.1.1 Git基础操作
- 6.1.2 Git基本原理
- 6.1.3 进一步了解Git
- 6.2 敏捷开发