Skip to content

9.1 Git 介绍

在项目中使用过 Git,不能代表真正的了解 Git。初级开发者使用推送(Push)、拉取(Pull)、合并(merge)三个命令可以完成 70% 的日常工作,但这些只占 Git 基础的 10%。当合并遇到冲突时,也许你会凭借对工具的熟悉解决掉冲突,然而有时候却又莫名其妙覆盖了别人的代码,为团队带来麻烦。

究其原因,还是没有深入理解 Git 的工作原理,更不要说各个命令背后的执行逻辑了。

若要真正地了解 Git,就不能从 Git 的角度认识它。这句话有点拗口,总之我们现在暂时抛开 Git,先去掌握一个重要的概念 ——— 版本控制。

9.1.1 什么是版本控制?

假设你现在要写一篇专业论文,全文大约五万字,需要写 30 天。这是一个长期任务,你不可能一口气写完五万字,一定是今天写一点,明天写一点,稳步进行的过程。

在长达 30 天的写作过程中,有没有可能会遇到以下情况:

  1. 某天电脑突然死机,没有保存,内容全丢了。
  2. 几天前写的内容,今天改废了,还想找回原来的内容。
  3. 论文太长,无意间修改/删除了已经写好的内容,自己却不知道。

以上三种情况,无论遇到哪一种,想必都会令人抓狂。那么有什么办法能避免这种情况呢?

可能大多数人会想到这个“笨办法”:写一部分存一部分。比如今天完成了一段内容,将它单独保存为一个文件;明天完成一段新的内容,再将其保存为另一个文件。这样即便某天整个文档都丢失了,之前保存的副本还在,就不至于整篇文章全部弄丢。

上述的“分段保存”思想确实解决了内容丢失的问题,但是弊端也很明显:已经完成的段落会大量重复地保存。假设保存了 10 个副本,那么每个副本中都有第一个段落的内容,这样不仅浪费资源,在之后的检索和恢复时也会带来困难。

经过工程师们的探索和实践,发现了另一种更好的实现,就是用“分段保存变化”来代替“分段保存内容”。什么意思呢?上面介绍的“笨办法”是将最新的内容整体保存为一个副本,事实上重复保存的内容并不需要。而“分段保存变化”的思想是只保存内容变化的部分,包括增加和删除,这样就避免了重复保存的弊端。

举个例子:假设我的论文已经写了 10000 字,现在又写了 2000 字的新内容。如果保存的话,我只需要将这 2000 字保存为副本,而不是将 12000 字重新保存一次。

对于这一段相比上次发生了变化的内容,我们称之为“版本”。有了版本之后,我们就可以在多个版本之间切换,这样可以随时查看或回到某个版本的内容,这个过程就被称为“版本控制”。

9.1.2 Git 工作原理

有了对版本控制的认识,我们从版本控制的角度理解 Git。

Git 是一个版本控制系统,本质上它是版本控制的一种实现。上面我们介绍了“保存版本”、“查看版本”、“恢复版本”等一系列版本控制的功能,这些功能都需要一个具体的工具来实现,Git 就是在众多的版本控制工具中最有代表性、也是当前最主流的觉色。

那么 Git 是如何实现版本控制的呢?接下来我们介绍其实现原理。

    1. Git 仓库

结合版本控制的概念我们知道,如果要保存文件的版本,首先要有一个存储版本的位置。在 Git 中,我们把这个存储版本的位置称为“仓库”。使用 Git 的第一步,就是初始化一个仓库。

仓库一般存储在项目的根目录下。假设现在有一个名为 git_demo 的文件夹,进入该文件夹并执行初始化命令:

$ git init

命令执行后会在 git_demo 文件夹下创建一个 .git 隐藏目录,这个目录就是我们通过命令创建的 Git 仓库。之后所有 git_demo 目录下的文件变化,都可以作为版本记录在这个仓库中。

    1. Git 快照

Git 对于不同版本的文件是如何保存的呢?答案是使用快照。

什么是快照?简单来说“快照”就是某个版本下所有文件的指向。当 Git 创建一个新版本时,它会生成一个快照,快照下包含了所有文件的索引(文件在内存中的引用),通过这些索引就可以找到这个快照下的所有文件。

Git 在生成快照时,首先会检测哪些文件发生了变化。对于修改了的文件,Git 会将该文件重新保存一份,并将这个新文件的索引添加到快照中;对于没有改变的文件,Git 直接使用原文件的索引,这样就不会重复保存没有变化的文件。

快照机制是 Git 与其他版本控制系统最大的区别。因为每个版本的快照都保存了所有文件的索引,因此 Git 在版本切换时非常迅速,不需要做任何差异比较,其版本更新原理如图 10-1 所示。

    1. 三种文件状态

Git 仓库用于存储版本,Git 快照与版本关联,是文件的保存方式。项目中的文件从修改到被添加到快照的过程中,一共会经历以下三种状态的变化:

  • 已修改(modified):修改了文件,还没有做标记。
  • 已暂存(staged):修改的文件已标记,下次提交时会被添加到快照中。
  • 已提交(committed):快照已创建,文件已包含在版本中。

与上述的三种状态对应的是,文件在不同状态时会存储在不同的位置,其状态与位置的对应关系如下:

  • modified 状态:文件在“工作区”。
  • staged 状态:文件在“暂存区”。
  • committed 状态:文件在 “Git 仓库”中。

工作区其实就是我们编辑代码的地方,能看到的代码都在工作区。暂存区是一个文件,保存了下次要提交(保存为快照)的文件列表。Git 仓库则是保存版本的地方,同时也保存了各个版本中提交的文件。

文件在不同位置切换的流程如图 10-2 所示。

基于此,我们可以总结基本的 Git 工作流程如下:

  1. 在工作区中修改文件。
  2. 将修改后的文件添加到暂存区。
  3. 创建版本,生成快照,将快照和新文件存储到 Git 仓库中。
  4. 切换版本,将不同版本的文件检出到工作区。

了解了 Git 的工作原理,在使用 Git 命令时就会更容易理解命令在做什么事,做到游刃有余。

9.1.3 安装 Git

创建 Git 仓库时我们提到了 “git init” 命令,若想这个命令正常运行,首先需要安装 Git。即便电脑中已经安装了 Git,也建议升级到最新版本,笔者当前使用的 Git 版本是 v2.37.1。

  1. Windows 安装

Windows 安装很简单,打开 Git 官网会看到下载,直接选择下载对应 Windows 系统的安装包即可。安装之后会全局创建一个 git 命令,你可以在控制台或编辑器终端使用该命令。

  1. MacOS 安装

MacOS 系统中一般不需要单独安装 Git,因为它已经包含在 Xcode 命令行工具中,我们只需要确保 Xcode 命令行工具已安装即可(开发者的电脑一般都会装这个工具)。

在终端执行一个 git 命令,查看输出结果:

sh
$ git -v

正常情况下会打印出当前的 Git 版本。如果你没有安装 Xcode 命令行工具,系统会提示安装。安装后再次执行上述命令,就能看到 Git 版本了。

  1. Linux 安装

常用的 Linux 系统包括 CentOS 和 Ubuntu 两类,两种系统分别提供了不同的包管理器。在 CentOS 中,可以直接使用 yum 来安装 Git:

$ yum install git

在 Ubuntu,使用 apt-get 来安装 Git:

$ sudo apt-apt install git

安装好命令,一切就绪,下面开始我们正式的 Git 探索之旅。