Git 内部:它是如何工作的以及 .git 文件夹的作用
Source: Dev.to
引言
对许多开发者来说,Git 像是一段神奇的咒语。我们输入 git add .,随后 git commit -m "fixed stuff",推送到远程服务器,并祈祷一切顺利。它运行时,简直太棒;一旦出错,就像在蒙着眼睛拆弹一样令人焦虑。
了解表面之下的工作原理可以把盲目的记忆转化为真正的掌握。Git 不仅仅是一堆命令;它是一个精心设计的信息管理系统。通过剥开层层包装,我们可以构建出 Git 实际“思考”方式的心智模型。
.git 文件夹
仓库的隐藏核心是 .git 文件夹。它通常在文件资源管理器中被隐藏,因为手动更改可能会损坏仓库。
- 工作目录 –
.git之外的所有内容;你编辑文件的沙盒。 .git文件夹 – 存储每个文件的每个版本、完整提交历史以及所有分支的数据库。
重要提示: 删除
.git文件夹会抹掉整个项目历史,只留下磁盘上当前可见的文件。
关键子目录和文件
| 路径 | 描述 |
|---|---|
objects/ | 存放所有文件内容和历史(数据库的核心)。 |
refs/ | 保存指针(引用),如分支(heads/)和标签。 |
HEAD | 一个纯文本文件,指示当前所在的分支。 |
Git 的工作方式类似键值存储。键是由内容生成的 40 位 SHA‑1 哈希。内容的任何改动都会产生完全不同的哈希,从而保证数据完整性。
Git 的数据模型
对象类型
Git 在 objects/ 中存储三种主要对象:
Blob
- 包含文件的原始内容。
- 不存储文件名或其位置。
- 不同文件中相同的内容会对应同一个共享的 Blob。
Tree
- 表示一个目录。
- 包含指向 Blob(文件)和其他 Tree(子目录)的条目,以及它们的文件名。
Commit
- 将所有内容组合成一次快照。
- 包含:
- 指向顶层 Tree 的指针(当时项目根目录的快照)。
- 元数据:作者、时间戳和提交信息。
- 指向父 Commit 的指针(前一次快照)。
理解这些对象有助于阐明 暂存区(也称 Index)的作用。
暂存区(Index)
Index 记录哪些 Blob 应该被包含在下一个快照中。
添加文件 (git add)
git add style.css
运行 git add 时:
- Git 将文件内容压缩为一个 Blob。
- 计算该 Blob 的 SHA‑1 哈希并将 Blob 存入
.git/objects/。 - 更新 Index,使
style.css映射到该 Blob 哈希,表明该文件应成为下次提交的一部分。
创建提交 (git commit)
git commit -m "Added Styles"
运行 git commit 时:
- Git 创建一个 Tree 对象,反映当前目录结构,使用 Index 中记录的 Blob 哈希。
- 创建一个 Commit 对象,指向该 Tree 并指向前一个 Commit。
- 将当前分支引用(例如
refs/heads/main)移动到新的 Commit 哈希。
通过将工作目录 → Blob → Tree → Commit 的流程可视化,你可以清晰地看到 Git 如何记录历史,以及为什么 git add 与 git commit 会表现出如此行为。