章节 ▾ 第二版

10.1 Git 内部原理 - 底层命令与上层命令

你可能是在阅读完前面的章节后跳到了这一章,或者是按顺序通读全书来到这里——无论哪种情况,我们都将在本章深入探讨 Git 的内部工作机制和实现方式。我们认为,理解这些信息对于领会 Git 的实用性和强大功能至关重要,但也有人向我们指出,这对于初学者来说可能会显得晦涩且过于复杂。因此,我们将这一部分的讨论放在了书的最后一章,这样你可以根据自己的进度决定是尽早阅读还是稍后阅读。选择权在你。

既然你已经到了这里,我们就开始吧。首先,如果还没搞清楚的话:Git 本质上是一个内容寻址(content-addressable)文件系统,并在其之上构建了一个版本控制系统(VCS)的用户界面。稍后你会进一步了解这意味着什么。

在 Git 的早期(主要是 1.5 版本之前),用户界面要复杂得多,因为它更侧重于这个文件系统本身,而不是一个完善的 VCS。在过去几年中,UI 经过了不断优化,已经变得像市面上任何系统一样简洁易用;然而,关于早期 Git UI 复杂难学的刻板印象依然存在。

内容寻址文件系统层非常酷,所以本章我们将首先介绍它;然后,你将了解传输机制以及你最终可能需要处理的仓库维护任务。

底层命令与上层命令(Plumbing and Porcelain)

本书主要介绍如何使用约 30 个左右的 Git 子命令,例如 checkoutbranchremote 等。但由于 Git 最初是一个版本控制系统的工具包,而非一个完整且友好的 VCS,它包含许多用于执行低级工作的子命令,这些命令设计为可以像 UNIX 工具那样链式调用,或者通过脚本调用。这些命令通常被称为 Git 的“底层命令”(plumbing),而那些更友好的用户界面命令则被称为“上层命令”(porcelain)。

正如你现在所注意到的,本书的前九章几乎只涉及上层命令。但在本章中,你将主要接触到底层命令,因为它们让你能够深入 Git 的内部运作,并展示 Git 为什么以及如何执行这些操作。这些命令中许多并不是为了在命令行上手动使用而设计的,而是作为构建新工具和自定义脚本的基石。

当你在一个新的或现有的目录中运行 git init 时,Git 会创建一个 .git 目录,几乎所有 Git 存储和操作的内容都位于此。如果你想备份或克隆你的仓库,复制这一个目录就几乎包含了你需要的一切。本章基本上就是讨论在这个目录下你能看到的内容。以下是一个刚初始化的 .git 目录通常的样子:

$ ls -F1
config
description
HEAD
hooks/
info/
objects/
refs/

根据你的 Git 版本,你可能会在那里看到一些额外内容,但这就是一个全新的 git init 仓库——这是默认显示的内容。description 文件仅供 GitWeb 程序使用,所以不用管它。config 文件包含你项目特定的配置选项,info 目录保存了一个全局排除文件,用于放置你不想在 .gitignore 文件中跟踪的忽略模式。hooks 目录包含你的客户端或服务器端钩子脚本,我们在 Git 钩子 中有详细讨论。

剩下的四个重要入口是:HEAD 文件、index 文件(尚未创建)、以及 objectsrefs 目录。这些是 Git 的核心部分。objects 目录存储数据库的所有内容,refs 目录存储指向这些数据中提交对象的指针(分支、标签、远程仓库等),HEAD 文件指向你当前检出的分支,而 index 文件是 Git 存储暂存区信息的地方。现在,你将详细研究每一个部分,看看 Git 是如何运作的。