.git 文件夹里有什么?
Source: Dev.to
Source:
介绍
在本文中,我们将打开引擎盖,看看驱动 Git 的 .git 文件夹。
阅读完本文后,你将了解:
- Git 如何在内部存储文件并跟踪历史。
- 提交是如何在内部构建的。
在深入十六进制的兔子洞之前,请确保你已经掌握了以下内容:
- 基本的 Git 命令 –
git add、git commit、git push。 - 命令行 – 使用
cd导航,使用ls列出文件等。 - 好奇心 – 愿意探索抽象概念。
新手使用 Git?
如果你需要复习基础知识,请查看:
- 轻松学 Git:版本控制入门指南
.git 文件夹
如果你在电脑上打开任意 Git 仓库并启用“显示隐藏文件”,就会看到一个名为 .git 的文件夹。
- 它不仅仅是一个配置文件夹——它是一个 数据库。
- 它是仓库的 大脑、心脏和灵魂。
- 删除项目文件 但保留
.git文件夹,就可以恢复所有内容。 - 删除
.git文件夹会把仓库变成普通的文本文件夹,所有历史记录都会丢失。
Git 本质上是一个 内容可寻址文件系统——换句话说,它是一个 键值存储。
核心 Git 对象
| 对象 | 存储内容 | 用途 |
|---|---|---|
| Blob | 原始文件内容(例如 main.ts)。Git 会压缩内容并以 blob 形式存储。 | 保存数据,但没有文件名。 |
| Tree | 目录结构。将文件名(例如 main.ts)映射到 blob ID,并且可以包含其他树(子目录)。 | 重建文件夹层次结构。 |
| Commit | 某一时刻的仓库快照。包含指向一个 tree 的指针、元数据(作者、日期、提交信息)以及指向父提交的指针。 | 将所有内容关联在一起,形成历史链。 |
简而言之
- Blob – 文件数据。
- Tree – 文件夹组织结构。
- Commit – 快照(谁、何时、为何)。
SHA‑1(及 SHA‑256)哈希
您可能已经看到过类似 a1b2c3d… 的长字符串。它们是 SHA‑1 哈希——通过对对象内容应用数学公式生成的 40 字符标识。
- SHA = 安全散列算法(Secure Hash Algorithm)。
- 更新的 Git 版本也支持 SHA‑256,但 SHA‑1 仍是默认,因为整个生态系统(GitHub、GitLab、各种工具)仍然依赖它。
检查仓库使用的哈希算法
git rev-parse --show-object-format
# Output: sha1 (or sha256)
rev-parse– 一个底层命令,用于解析和处理 Git 引用。--show-object-format– 显示仓库使用的对象哈希格式。
从编辑器到仓库
步骤 1 – git add .
发生了什么:
- Git 读取每个已修改文件的内容。
- 为这些内容创建 blob 对象 并将其存放在
.git/objects中。 - 更新 索引(暂存区)——一个列表,记录“在下次提交时,这个文件名指向这个 blob 哈希”。
步骤 2 – git commit -m "Message"
发生了什么:
- 树对象创建 – Git 遍历索引,构建表示当前文件夹结构的树对象。
- 提交对象创建 – 创建一个提交对象,指向顶层树以及前一次提交(即它的父提交)。
- HEAD 更新 –
HEAD指针(当前分支标签)被移动到新的提交 ID。
完整性魔法
- 文件的哈希值(例如,
"Hello World")始终保持不变。 - 更改内容(例如,
"Hello Worlds")会产生完全不同的哈希值。 - Git 不仅对内容进行哈希,还包括对象类型和大小,从而保证唯一性和完整性。
由于每个提交都会存储其父提交的哈希,整个历史形成了一个密码学链——对任何对象进行篡改都会导致链断裂。
HEAD 文件
HEAD 是一个小型文本文件,用来告诉 Git 你当前所在的工作位置。典型内容:
ref: refs/heads/main
- 这表示“我们位于
main分支”。 - 执行
git checkout dark-mode只会将HEAD更新为ref: refs/heads/dark-mode。
.git 目录内部
| 目录 / 文件 | 用途 |
|---|---|
| objects/ | 存储所有 Git 对象(blobs、trees、commits、tags),文件名为它们的 SHA‑1 哈希。 |
| refs/ | 书签目录——分支和标签。 |
| refs/heads/ | 每个分支的文件(例如 feature-login)。每个文件包含一个 40 字符的提交哈希。 |
| HEAD | 指向当前分支(或在分离的 HEAD 状态下直接指向某个提交)。 |
| index | 二进制暂存区。由 git add 更新;保存时间戳、文件名和准备在下次提交时使用的 blob 哈希。 |
检查对象
对象以压缩的二进制形式存储,因此使用 git cat-file 打开它们:
git cat-file -p <object-id>
# -p = pretty‑print(人类可读)
提交对象的示例输出
tree 8d3a1...
parent 1f4e2...
author Satpal Rana 1703865000 +0000
Created the homepage hero section
摘要
.git文件夹是一个功能完整的数据库,存放 blobs、trees、commits 和 references。- Git 的内容可寻址存储使用 SHA‑1(或可选的 SHA‑256)哈希来保证完整性。
- 添加文件会创建 blobs 并更新 index;提交时会构建 trees 和提交对象,然后移动 HEAD。
- 分支是指向提交哈希的轻量指针,使得创建和切换分支非常快速。
现在,你可以清晰地看到每次运行 Git 命令时在 内部 发生了什么。祝你探索愉快!
动手实践 Git
仓库配置
此文本文件包含特定于此仓库的配置,例如:
- 远程仓库的 URL(
origin)。 - 本地用户覆盖设置。
- 分支跟踪信息。
创建新仓库
git init demo
cd demo
创建文件并提交
echo "Hello Git" > hello.txt
git add .
git commit -m "First commit"
探索对象
# List the objects stored in the repository
ls .git/objects
# Show the contents of a specific object (replace <sha> with an actual SHA‑1)
git cat-file -p <sha>
观察 Git 如何在内部存储和检索数据。
结论
在本文中,我们探讨了 Git 如何使用 blobs、trees、commits 和 hashes 在内部存储数据。理解这些后,Git 就不再显得神秘,而是更可预测。
“隐藏的文件夹有时藏着最大的秘密。”
— 匿名开发者