章节 ▾ 第二版

1.3 入门 - Git 是什么?

什么是 Git?

那么,简而言之,Git 是什么?这一节很重要,务必理解,因为如果你明白了 Git 是什么以及它工作的基础原理,那么高效地使用 Git 就会变得容易得多。在学习 Git 的过程中,尽量忘掉你可能了解过的其他版本控制系统(VCS),例如 CVS、Subversion 或 Perforce —— 这样做有助于你在使用 Git 时避免产生细微的混淆。尽管 Git 的用户界面与其他 VCS 相当相似,但 Git 存储和思考信息的方式却截然不同,理解这些差异将有助于你避免在使用过程中感到困惑。

快照,而非差异

Git 与其他任何 VCS(包括 Subversion 及其同类产品)的主要区别在于 Git 如何看待其数据。从概念上讲,大多数其他系统将信息存储为基于文件的更改列表。这些其他系统(CVS、Subversion、Perforce 等)将它们存储的信息视为一组文件以及每个文件随时间发生的变化(这通常被描述为基于增量的版本控制)。

Storing data as changes to a base version of each file
图 4. 以基准版本的更改来存储数据

Git 不以这种方式思考或存储其数据。相反,Git 将其数据更像一系列的迷你文件系统快照。在 Git 中,每次提交或保存项目状态时,Git 基本上都会拍一张当时所有文件样子的照片,并存储对该快照的引用。为了高效,如果文件没有更改,Git 不会再次存储该文件,只会在已存储的先前相同文件上创建一个链接。Git 将其数据更像一个**快照流**。

Git stores data as snapshots of the project over time
图 5. 随时间推移存储项目快照的数据

这是 Git 与几乎所有其他 VCS 之间的一个重要区别。它使得 Git 能够重新审视大多数其他系统从上一代继承而来的几乎每一个版本控制的方面。这使得 Git 更像一个迷你文件系统,上面构建了一些极其强大的工具,而不仅仅是一个 VCS。当我们讨论 Git 分支 时,我们将探讨通过这种方式思考数据能带来的一些好处。

几乎所有操作都是本地的

Git 中的大多数操作只需要本地文件和资源即可运行 —— 通常不需要网络上的另一台计算机的任何信息。如果你习惯使用 CVCS,其中大多数操作都存在网络延迟的开销,那么 Git 的这一点会让你觉得速度之神似乎赋予了 Git 超凡的力量。因为项目的完整历史记录就在你的本地磁盘上,所以大多数操作似乎几乎是瞬时的。

例如,要浏览项目历史,Git 不需要连接到服务器获取历史并显示给你 —— 它只需从本地数据库直接读取。这意味着你几乎可以立即看到项目历史。如果你想查看当前版本的文件与一个月前的文件之间的差异,Git 可以查找一个月前的文件并进行本地差异计算,而无需询问远程服务器来执行此操作,或者从远程服务器拉取一个较旧的文件版本来本地执行。

这意味着,如果你离线或没有 VPN,你可以做的几乎事情都很少。如果你坐上飞机或火车,想做点工作,你可以愉快地提交(请记住,提交到你的本地副本!),直到你连接到网络才能上传。如果你回到家,VPN 客户端无法正常工作,你仍然可以工作。在许多其他系统中,这样做要么不可能,要么非常痛苦。例如,在 Perforce 中,当未连接到服务器时,你无法做太多事情;在 Subversion 和 CVS 中,你可以编辑文件,但无法将更改提交到你的数据库(因为你的数据库离线)。这可能看起来不是什么大事,但你可能会惊讶于它能带来如此大的不同。

Git 具有完整性

Git 中的所有内容在存储之前都会进行校验和计算,然后根据该校验和进行引用。这意味着在 Git不知情的情况下,文件或目录的内容被更改是不可能的。这个功能是 Git 在最低级别上构建的,也是其哲学不可或缺的一部分。你不会在传输过程中丢失信息,也不会在 Git 无法检测到的情况下发生文件损坏。

Git 使用的校验和机制称为 SHA-1 哈希。这是一个由十六进制字符(0-9 和 a-f)组成的 40 位字符串,根据 Git 中文件或目录结构的内容计算得出。SHA-1 哈希值看起来像这样

24b9da6552252987aa493b52f8696cd6d3b00373

你会在 Git 中到处看到这些哈希值,因为 Git 大量使用它们。实际上,Git 在其数据库中存储内容不是按文件名,而是按其内容计算出的哈希值。

Git 通常只添加数据

当你执行 Git 操作时,几乎所有操作都只是添加数据到 Git 数据库。要让系统执行任何不可撤销的操作或以任何方式擦除数据,都是很困难的。与任何 VCS 一样,你可能会丢失或弄糟尚未提交的更改,但一旦你将快照提交到 Git,就很难丢失,特别是如果你定期将数据库推送到另一个仓库。

这使得使用 Git 成为一种乐趣,因为我们知道我们可以进行实验,而不会有严重搞砸的危险。有关 Git 如何存储其数据以及如何恢复似乎丢失的数据的更深入的介绍,请参阅 撤销操作

三个状态

现在请注意 —— 如果你希望后续的学习过程顺利进行,这是关于 Git 最重要的一点要记住。Git 中你的文件可以存在于三个主要状态:已修改(modified)、已暂存(staged)和已提交(committed)。

  • 已修改(Modified)表示你更改了文件,但尚未将其提交到数据库。

  • 已暂存(Staged)表示你已将某个已修改文件的当前版本标记为将包含在下一个提交快照中。

  • 已提交(Committed)表示数据已安全地存储在你的本地数据库中。

这引出了 Git 项目的三个主要部分:工作目录(working tree)、暂存区域(staging area)和 Git 目录(Git directory)。

Working tree, staging area, and Git directory
图 6. 工作目录、暂存区域和 Git 目录

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

暂存区域是一个文件,通常包含在你的 Git 目录中,它存储了有关将要包含在下一个提交中的信息。在 Git 的专业术语中,它的技术名称是“索引”(index),但“暂存区域”(staging area)这个说法也同样好用。

Git 目录是 Git 存储项目元数据和对象数据库的地方。这是 Git 最重要的部分,当你从另一台计算机克隆(clone)一个仓库时,它会被复制。

基本的 Git 工作流程大致如下:

  1. 你在工作目录中修改文件。

  2. 你选择性地暂存你想包含在下一次提交中的更改,这会将这些更改添加到暂存区域。

  3. 你执行提交操作,该操作将暂存区域中的文件作为当前状态,并将该快照永久存储到你的 Git 目录中。

如果一个文件的某个特定版本存在于 Git 目录中,它就被认为是已提交(committed)。如果它被修改并添加到了暂存区域,那么它就是已暂存(staged)。如果它自检出以来被修改但尚未暂存,那么它就是已修改(modified)。在 Git 基础 中,你将学到更多关于这些状态的信息,以及如何利用它们或完全跳过暂存部分。