章节 ▾ 第二版

1.3 起步 - 什么是 Git?

什么是 Git?

那么,Git 究竟是什么呢?这一节非常重要,需要细心理解。如果你理解了 Git 是什么以及它如何工作的基础原理,那么有效使用 Git 就会容易得多。在学习 Git 的过程中,尽量清空你对其他版本控制系统(如 CVS、Subversion 或 Perforce)的认知——这样做有助于避免在使用该工具时产生微妙的混淆。尽管 Git 的用户界面与其他版本控制系统相当相似,但 Git 存储和思考信息的方式却大不相同,理解这些差异将有助于你在使用时避免困惑。

快照,而不是差异

Git 与任何其他版本控制系统(包括 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 与几乎所有其他版本控制系统之间的一个重要区别。它使得 Git 重新考虑了大多数其他系统从上一代复制过来的版本控制的几乎所有方面。这使得 Git 更像一个带有强大工具的迷你文件系统,而不仅仅是一个版本控制系统。当我们在Git 分支中介绍 Git 分支时,我们将探讨以这种方式思考数据所带来的一些好处。

几乎所有操作都是本地的

Git 中的大多数操作只需要本地文件和资源即可执行——通常不需要网络上另一台计算机的信息。如果你习惯了大多数操作都有网络延迟开销的集中式版本控制系统,那么 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 中,就很难丢失,特别是如果你定期将数据库推送到另一个仓库。

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

三种状态

现在请注意——这是关于 Git 最重要的一点,如果你想让接下来的学习过程顺利进行。Git 有三种主要状态,你的文件可以处于其中:*已修改*、*已暂存*和*已提交*。

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

  • 已暂存表示你已将修改后的文件当前版本标记为要包含在下一次提交快照中。

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

这导致我们进入 Git 项目的三个主要部分:工作区、暂存区和 Git 目录。

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

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

暂存区是一个文件,通常包含在你的 Git 目录中,它存储着关于下一次提交将包含什么的信息。它在 Git 术语中的技术名称是“索引”,但“暂存区”这个词也同样适用。

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

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

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

  2. 你选择性地暂存你希望成为下一次提交的一部分的那些更改,这会*只*将这些更改添加到暂存区。

  3. 你执行提交操作,它会获取暂存区中的文件,并将其快照永久存储到你的 Git 目录中。

如果文件的特定版本在 Git 目录中,则它被认为是*已提交*。如果它已修改并添加到暂存区,则它处于*已暂存*状态。如果它自检出以来已更改但尚未暂存,则它处于*已修改*状态。在Git 基础中,你将了解更多关于这些状态以及如何利用它们或完全跳过暂存部分。