9.1 Git 介绍
在项目中使用过 Git,不能代表真正的了解 Git。初级开发者使用推送(Push)、拉取(Pull)、合并(merge)三个命令可以完成 70% 的日常工作,但这些只占 Git 基础的 10%。当合并遇到冲突时,也许你会凭借对工具的熟悉解决掉冲突,然而有时候却又莫名其妙覆盖了别人的代码,为团队带来麻烦。
究其原因,还是没有深入理解 Git 的工作原理,更不要说各个命令背后的执行逻辑了。
若要真正地了解 Git,就不能从 Git 的角度认识它。这句话有点拗口,总之我们现在暂时抛开 Git,先去掌握一个重要的概念 ——— 版本控制。
9.1.1 什么是版本控制?
假设你现在要写一篇专业论文,全文大约五万字,需要写 30 天。这是一个长期任务,你不可能一口气写完五万字,一定是今天写一点,明天写一点,稳步进行的过程。
在长达 30 天的写作过程中,有没有可能会遇到以下情况:
- 某天电脑突然死机,没有保存,内容全丢了。
- 几天前写的内容,今天改废了,还想找回原来的内容。
- 论文太长,无意间修改/删除了已经写好的内容,自己却不知道。
以上三种情况,无论遇到哪一种,想必都会令人抓狂。那么有什么办法能避免这种情况呢?
可能大多数人会想到这个“笨办法”:写一部分存一部分。比如今天完成了一段内容,将它单独保存为一个文件;明天完成一段新的内容,再将其保存为另一个文件。这样即便某天整个文档都丢失了,之前保存的副本还在,就不至于整篇文章全部弄丢。
上述的“分段保存”思想确实解决了内容丢失的问题,但是弊端也很明显:已经完成的段落会大量重复地保存。假设保存了 10 个副本,那么每个副本中都有第一个段落的内容,这样不仅浪费资源,在之后的检索和恢复时也会带来困难。
经过工程师们的探索和实践,发现了另一种更好的实现,就是用“分段保存变化”来代替“分段保存内容”。什么意思呢?上面介绍的“笨办法”是将最新的内容整体保存为一个副本,事实上重复保存的内容并不需要。而“分段保存变化”的思想是只保存内容变化的部分,包括增加和删除,这样就避免了重复保存的弊端。
举个例子:假设我的论文已经写了 10000 字,现在又写了 2000 字的新内容。如果保存的话,我只需要将这 2000 字保存为副本,而不是将 12000 字重新保存一次。
对于这一段相比上次发生了变化的内容,我们称之为“版本”。有了版本之后,我们就可以在多个版本之间切换,这样可以随时查看或回到某个版本的内容,这个过程就被称为“版本控制”。
9.1.2 Git 工作原理
有了对版本控制的认识,我们从版本控制的角度理解 Git。
Git 是一个版本控制系统,本质上它是版本控制的一种实现。上面我们介绍了“保存版本”、“查看版本”、“恢复版本”等一系列版本控制的功能,这些功能都需要一个具体的工具来实现,Git 就是在众多的版本控制工具中最有代表性、也是当前最主流的觉色。
那么 Git 是如何实现版本控制的呢?接下来我们介绍其实现原理。
- Git 仓库
结合版本控制的概念我们知道,如果要保存文件的版本,首先要有一个存储版本的位置。在 Git 中,我们把这个存储版本的位置称为“仓库”。使用 Git 的第一步,就是初始化一个仓库。
仓库一般存储在项目的根目录下。假设现在有一个名为 git_demo 的文件夹,进入该文件夹并执行初始化命令:
$ git init
命令执行后会在 git_demo 文件夹下创建一个 .git 隐藏目录,这个目录就是我们通过命令创建的 Git 仓库。之后所有 git_demo 目录下的文件变化,都可以作为版本记录在这个仓库中。
- Git 快照
Git 对于不同版本的文件是如何保存的呢?答案是使用快照。
什么是快照?简单来说“快照”就是某个版本下所有文件的指向。当 Git 创建一个新版本时,它会生成一个快照,快照下包含了所有文件的索引(文件在内存中的引用),通过这些索引就可以找到这个快照下的所有文件。
Git 在生成快照时,首先会检测哪些文件发生了变化。对于修改了的文件,Git 会将该文件重新保存一份,并将这个新文件的索引添加到快照中;对于没有改变的文件,Git 直接使用原文件的索引,这样就不会重复保存没有变化的文件。
快照机制是 Git 与其他版本控制系统最大的区别。因为每个版本的快照都保存了所有文件的索引,因此 Git 在版本切换时非常迅速,不需要做任何差异比较,其版本更新原理如图 10-1 所示。
- 三种文件状态
Git 仓库用于存储版本,Git 快照与版本关联,是文件的保存方式。项目中的文件从修改到被添加到快照的过程中,一共会经历以下三种状态的变化:
- 已修改(modified):修改了文件,还没有做标记。
- 已暂存(staged):修改的文件已标记,下次提交时会被添加到快照中。
- 已提交(committed):快照已创建,文件已包含在版本中。
与上述的三种状态对应的是,文件在不同状态时会存储在不同的位置,其状态与位置的对应关系如下:
- modified 状态:文件在“工作区”。
- staged 状态:文件在“暂存区”。
- committed 状态:文件在 “Git 仓库”中。
工作区其实就是我们编辑代码的地方,能看到的代码都在工作区。暂存区是一个文件,保存了下次要提交(保存为快照)的文件列表。Git 仓库则是保存版本的地方,同时也保存了各个版本中提交的文件。
文件在不同位置切换的流程如图 10-2 所示。
基于此,我们可以总结基本的 Git 工作流程如下:
- 在工作区中修改文件。
- 将修改后的文件添加到暂存区。
- 创建版本,生成快照,将快照和新文件存储到 Git 仓库中。
- 切换版本,将不同版本的文件检出到工作区。
了解了 Git 的工作原理,在使用 Git 命令时就会更容易理解命令在做什么事,做到游刃有余。
9.1.3 安装 Git
创建 Git 仓库时我们提到了 “git init” 命令,若想这个命令正常运行,首先需要安装 Git。即便电脑中已经安装了 Git,也建议升级到最新版本,笔者当前使用的 Git 版本是 v2.37.1。
- Windows 安装
Windows 安装很简单,打开 Git 官网会看到下载,直接选择下载对应 Windows 系统的安装包即可。安装之后会全局创建一个 git 命令,你可以在控制台或编辑器终端使用该命令。
- MacOS 安装
MacOS 系统中一般不需要单独安装 Git,因为它已经包含在 Xcode 命令行工具中,我们只需要确保 Xcode 命令行工具已安装即可(开发者的电脑一般都会装这个工具)。
在终端执行一个 git 命令,查看输出结果:
$ git -v
正常情况下会打印出当前的 Git 版本。如果你没有安装 Xcode 命令行工具,系统会提示安装。安装后再次执行上述命令,就能看到 Git 版本了。
- Linux 安装
常用的 Linux 系统包括 CentOS 和 Ubuntu 两类,两种系统分别提供了不同的包管理器。在 CentOS 中,可以直接使用 yum 来安装 Git:
$ yum install git
在 Ubuntu,使用 apt-get 来安装 Git:
$ sudo apt-apt install git
安装好命令,一切就绪,下面开始我们正式的 Git 探索之旅。