=== Git 基础

那么，简单地说，Git 究竟是怎样的一个系统呢？
请注意接下来的内容非常重要，若你理解了 Git 的思想和基本工作原理，用起来就会知其所以然，游刃有余。
在开始学习 Git 的时候，请努力分清你对其它版本管理系统的已有认识，如 Subversion 和 Perforce 等；这么做能帮助你使用工具时避免发生混淆。
Git 在保存和对待各种信息的时候与其它版本控制系统有很大差异，尽管操作起来的命令形式非常相近，理解这些差异将有助于防止你使用中的困惑。(((Subversion)))(((Perforce)))

==== 直接记录快照，而非差异比较

Git 和其它版本控制系统（包括 Subversion 和近似工具）的主要差别在于 Git 对待数据的方法。
概念上来区分，其它大部分系统以文件变更列表的方式存储信息。
这类系统（CVS、Subversion、Perforce、Bazaar 等等）将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。

.存储每个文件与初始版本的差异.
image::images/deltas.png[存储每个文件与初始版本的差异。]

Git 不按照以上方式对待或保存数据。
反之，Git 更像是把数据看作是对小型文件系统的一组快照。
每次你提交更新，或在 Git 中保存项目状态时，它主要对当时的全部文件制作一个快照并保存这个快照的索引。
为了高效，如果文件没有修改，Git 不再重新存储该文件，而是只保留一个链接指向之前存储的文件。
Git 对待数据更像是一个 *快照流*。

.存储项目随时间改变的快照.
image::images/snapshots.png[Git 存储项目随时间改变的快照。]

这是 Git 与几乎所有其它版本控制系统的重要区别。
因此 Git 重新考虑了以前每一代版本控制系统延续下来的诸多方面。
Git 更像是一个小型的文件系统，提供了许多以此为基础构建的超强工具，而不只是一个简单的 VCS。
稍后我们在<<ch03-git-branching#ch03-git-branching>>讨论 Git 分支管理时，将探究这种方式对待数据所能获得的益处。

==== 近乎所有操作都是本地执行

在 Git 中的绝大多数操作都只需要访问本地文件和资源，一般不需要来自网络上其它计算机的信息。
如果你习惯于所有操作都有网络延时开销的集中式版本控制系统，Git 在这方面会让你感到速度之神赐给了 Git 超凡的能量。
因为你在本地磁盘上就有项目的完整历史，所以大部分操作看起来瞬间完成。

举个例子，要浏览项目的历史，Git 不需外连到服务器去获取历史，然后再显示出来——它只需直接从本地数据库中读取。
你能立即看到项目历史。
如果你想查看当前版本与一个月前的版本之间引入的修改，Git 会查找到一个月前的文件做一次本地的差异计算，而不是由远程服务器处理或从远程服务器拉回旧版本文件再来本地处理。

这也意味着你离线或者没有 VPN 时，几乎可以进行任何操作。
如你在飞机或火车上想做些工作，你能愉快地提交，直到有网络连接时再上传。
如你回家后 VPN 客户端不正常，你仍能工作。
使用其它系统，做到如此是不可能或很费力的。
比如，用 Perforce，你没有连接服务器时几乎不能做什么事；用 Subversion 和 CVS，你能修改文件，但不能向数据库提交修改（因为你的本地数据库离线了）。
这看起来不是大问题，但是你可能会惊喜地发现它带来的巨大的不同。

==== Git 保证完整性

Git 中所有数据在存储前都计算校验和，然后以校验和来引用。
这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。
这个功能建构在 Git 底层，是构成 Git 哲学不可或缺的部分。
若你在传送过程中丢失信息或损坏文件，Git 就能发现。

Git 用以计算校验和的机制叫做 SHA-1 散列（hash，哈希）。(((SHA-1)))
这是一个由 40 个十六进制字符（0-9 和 a-f）组成的字符串，基于 Git 中文件的内容或目录结构计算出来。
SHA-1 哈希看起来是这样：

[source]
----
24b9da6552252987aa493b52f8696cd6d3b00373
----

Git 中使用这种哈希值的情况很多，你将经常看到这种哈希值。
实际上，Git 数据库中保存的信息都是以文件内容的哈希值来索引，而不是文件名。

==== Git 一般只添加数据

你执行的 Git 操作，几乎只往 Git 数据库中增加数据。
很难让 Git 执行任何不可逆操作，或者让它以任何方式清除数据。
同别的 VCS 一样，未提交更新时有可能丢失或弄乱修改的内容；但是一旦你提交快照到 Git 中，就难以再丢失数据，特别是如果你定期的推送数据库到其它仓库的话。

这使得我们使用 Git 成为一个安心愉悦的过程，因为我们深知可以尽情做各种尝试，而没有把事情弄糟的危险。
更深度探讨 Git 如何保存数据及恢复丢失数据的话题，请参考<<ch02-git-basics#r_undoing>>。

==== 三种状态

好，请注意。
如果你希望后面的学习更顺利，记住下面这些关于 Git 的概念。
Git 有三种状态，你的文件可能处于其中之一：已提交（committed）、已修改（modified）和已暂存（staged）。
已提交表示数据已经安全的保存在本地数据库中。
已修改表示修改了文件，但还没保存到数据库中。
已暂存表示对一个已修改文件的当前版本做了标记，使之包含在下次提交的快照中。

由此引入 Git 项目的三个工作区域的概念：Git 仓库、工作目录以及暂存区域。

.工作目录、暂存区域以及 Git 仓库.
image::images/areas.png[工作目录、暂存区域以及 Git 仓库。]

Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。
这是 Git 中最重要的部分，从其它计算机克隆仓库时，拷贝的就是这里的数据。

工作目录是对项目的某个版本独立提取出来的内容。
这些从 Git 仓库的压缩数据库中提取出来的文件，放在磁盘上供你使用或修改。

暂存区域是一个文件，保存了下次将提交的文件列表信息，一般在 Git 仓库目录中。
有时候也被称作“索引”，不过一般说法还是叫暂存区域。

基本的 Git 工作流程如下：

1. 在工作目录中修改文件。
2. 暂存文件，将文件的快照放入暂存区域。
3. 提交更新，找到暂存区域的文件，将快照永久性存储到 Git 仓库目录。

如果 Git 目录中保存着特定版本的文件，就属于已提交状态。
如果作了修改并已放入暂存区域，就属于已暂存状态。
如果自上次取出后，作了修改但还没有放到暂存区域，就是已修改状态。
在<<ch02-git-basics#ch02-git-basics>>一章，你会进一步了解这些状态的细节，并学会如何根据文件状态实施后续操作，以及怎样跳过暂存直接提交。
