把 Git 想象成一个数据库
Git 官方定义是 内容寻址文件系统(Content-Addressable Filesystem),本质是一个 键值对数据库:
| 步骤 | 说明 |
|---|---|
| 输入 | 给 Git 一些内容(如文件) |
| 计算 | 对文件内容生成 SHA-1 哈希值(40 个字符) |
| 存储 | 哈希值作为 键,原始内容作为 值 |
关键:Git 认的是 内容本身,不是文件名。相同内容的文件只会生成同一个哈希,只存一份——这就是 Git 高效 数据去重 的秘密。
三种核心对象
commit (项目快照)
└── tree (目录结构)
├── blob (文件内容)
├── blob (文件内容)
└── tree (子目录)
└── blob (文件内容)
Blob — 文件内容
- 触发命令:
git add - 只包含纯粹的文件内容,不管文件名、路径、权限
- 10 个内容相同的配置文件 → 只生成 1 个 blob 对象(去重)
Tree — 目录结构
- 类似文件夹,维护一张清单:有哪些文件 → blob,有哪些子目录 → tree
- 每个条目附带文件名和权限信息
Commit — 项目快照
- 触发命令:
git commit - 包含:root tree(完整快照)、parent(上一次提交)、作者/时间/信息
blob = 文档内容,tree = 文件夹结构,commit = 全局快照。
分支的本质:一个 40 字节的文件
一个普遍的误解:创建分支 = 复制整个项目。
真相:分支只是一个指针——.git/refs/heads/main 文件里只有一行 40 字符的 SHA-1 哈希值。
创建分支:写入一个新文件(如 .git/refs/heads/dev)
新建提交:用新哈希值覆盖 refs 文件
切换分支:更新 HEAD 指向对应的 refs 文件
分支操作的本质是一次 文件写入,所以创建和切换能 快如闪电。
设计优越性
| 特性 | 原因 |
|---|---|
| 创建分支极快 | 只是创建一个 40 字节的文件 |
| 数据安全可靠 | 哈希值是内容指纹,任何损坏立刻可检测 |
| 存储空间高效 | 相同内容只存一份(blob 去重) |
| 历史不可篡改 | commit 一旦创建就无法修改 |
危险操作的可恢复性
核心判断原则:只要内容曾进入过 .git/objects/(被 add 或 commit 过),就有恢复的可能。反之,彻底没了。
能恢复的操作
| 操作 | 恢复方式 | 原理 |
|---|---|---|
git reset --hard HEAD~3 |
git reflog → git reset --hard <hash> |
commit 对象仍在 |
git commit --amend |
git reflog → git reset --hard <old-hash> |
原 commit 未删除 |
git rebase |
git reflog → git reset --hard <pre-rebase> |
旧 commit 仍存在 |
git branch -D 误删分支 |
git reflog → git checkout -b <name> <hash> |
指针删了,对象还在 |
git stash drop |
git fsck --dangling 找悬空 commit |
stash 也是 commit |
恢复通用套路:
bash
# 查看 HEAD 移动轨迹
git reflog
# 找到想回到的那个点,强制跳转
git reset --hard <hash>
不能恢复的操作
| 操作 | 不可恢复原因 |
|---|---|
git clean -fd 删除未跟踪文件 |
从未进入 Git 数据库 |
git checkout -- . 丢弃未暂存修改 |
没被 add 过 |
git reflog expire --expire=now --all + git gc --prune=now |
终极不可逆 |
判断流程
内容曾进入 Git 数据库?(add/commit 过)
├─ 是 → reflog 还在?→ 能恢复 ✅
└─ 否 → 不能恢复 ❌(等同于 rm)
安全建议
- 危险操作前先
git stash或git commit -m "wip" - reflog 默认保留 90 天,重要操作后尽快确认
- push 是终极保险:远程始终有一份
git clean前先用-n预览
总结
Git 的核心心法:Git = 由 blob、tree、commit 对象组成的数据库 + 分支是指向 commit 的指针。带着这个模型理解
reset、rebase等命令——它们本质上都是在操作对象和指针。Git 将不再是黑盒子。
