底层命令与上层命令
当我们日常使用 Git 时,我们通常使用的是 git add、git commit、git checkout 等命令。这些命令被设计得尽可能用户友好,它们就像汽车的仪表盘和方向盘,让我们能够轻松驾驶。
然而,在这些命令之下,Git 还包含了一套更为基础、底层的命令。这些命令被称为 底层命令 (Plumbing commands),而那些我们日常使用的命令则被称为 上层命令 (Porcelain commands)。
本章将带你揭开 Git 的引擎盖,看看它内部是如何运转的。
什么是上层命令 (Porcelain)?
Section titled “什么是上层命令 (Porcelain)?”Porcelain 一词直译为“瓷器”,在这里引申为精致、包装好的接口。
上层命令是 Git 专门为普通用户设计的接口。它们具有以下特点:
- 用户友好:提供清晰的输出、帮助信息和进度条。
- 抽象:将复杂的内部操作封装成简单的逻辑动作(例如
git commit实际上执行了创建树对象、创建提交对象、更新引用等多个步骤)。 - 安全:包含许多检查机制,防止用户误操作导致数据丢失。
常见例子:
git addgit commitgit statusgit pull
什么是底层命令 (Plumbing)?
Section titled “什么是底层命令 (Plumbing)?”Plumbing 一词直译为“管道”,意指底层的管道设施。
底层命令是 Git 的核心,它们直接操作 Git 的核心数据结构(对象数据库和索引)。它们通常用于:
- 脚本编写:由于输出格式稳定且不包含多余的装饰信息,非常适合被脚本解析。
- 调试:帮助理解 Git 内部状态。
- 实现上层命令:早期的 Git 上层命令其实就是由 shell 脚本调用这些底层命令组成的。
常见例子:
git hash-object:计算内容的哈希值并写入数据库。git cat-file:查看对象的内容或类型。git update-index:手动更新暂存区。git write-tree:将暂存区内容写入树对象。
实战:手动创建一个 Git 对象
Section titled “实战:手动创建一个 Git 对象”为了理解这两者的区别,我们尝试不使用 git add,而是使用底层命令将数据存入 Git 数据库。
首先,初始化一个新的仓库用于测试:
mkdir git-internals-democd git-internals-demogit init1. 使用 hash-object 存储数据
Section titled “1. 使用 hash-object 存储数据”git hash-object 命令可以计算数据的 SHA-1 哈希值,如果加上 -w 参数,它还会将数据写入 .git/objects 目录。
echo "Hello, Git Internals!" | git hash-object -w --stdin输出(你的哈希值可能略有不同,取决于换行符等细节):
a0423896973644771497bdc03eb99d5281615b51这个 40 位的十六进制字符串就是这条内容的“指纹”。此时,Git 已经将这段内容作为 Blob 对象 存储在 .git/objects/a0/4238... 文件中了。
2. 使用 cat-file 读取数据
Section titled “2. 使用 cat-file 读取数据”我们可以使用 git cat-file 来检查刚刚写入的内容。
查看对象类型:
git cat-file -t a0423896973644771497bdc03eb99d5281615b51blob查看对象内容:
git cat-file -p a0423896973644771497bdc03eb99d5281615b51Hello, Git Internals!- Porcelain (上层命令):给人用的。我们在日常开发中 99% 的时间都在用它。
- Plumbing (底层命令):给机器和脚本用的。它是 Git 强大的基石。
理解底层命令能帮助我们理解 Git 是如何管理数据的。接下来的章节,我们将深入探讨 Git 的四种核心对象类型,看看它们是如何构建出我们熟悉的项目历史的。