跳转到主要内容
返回文章列表

Git 数据模型基础概念

Others4 分钟阅读 · 1391
#Others#Git#版本控制#数据模型

问题

Git 所说的“快照”到底是什么意思?为什么 Git 不像传统版本控制那样主要存差异?这样不会很浪费空间吗?

回答

核心结论

Git 的核心思路不是“记录某次改动长什么样”,而是:

  • 记录 某一时刻整个目录树的状态
  • 用对象复用、压缩和打包机制避免重复存储

所以“Git 存快照”不等于“每次都傻乎乎把所有文件完整复制一遍”。更准确地说:

Git 记录的是一次提交对应的目录树快照,而未变化的对象会被复用。

快照和差异的区别

方式 关注点 直观理解
差异模型 这次改了什么 第 2 行从 A 变成 B
快照模型 当前整体是什么样 此刻项目目录树长什么样

传统版本控制更偏向“补丁思维”,Git 更偏向“状态思维”。

Git 为什么偏爱快照思维

主要因为它带来三个好处:

  1. 读取历史更直接:恢复某次提交时,不需要一层层回放补丁
  2. 分支和合并更自然:分支本质上只是指向某个提交的指针
  3. 对象模型更统一:文件内容、目录结构、提交记录都能抽象成对象图

为什么不会严重浪费空间

Git 主要靠三类机制控制空间占用:

1. 相同内容只存一份

相同文件内容会对应同一个 blob 对象。

提交 A ─┐
       ├─> blob(Hello)
提交 B ─┘

只要内容没变,Git 就不会重复创建新的内容对象。

2. 目录树按层复用

如果一个大型项目里只改了一个文件,那么:

  • 变化的 blob 会变
  • 受影响路径上的 tree 会变
  • 其他未变化的对象会继续复用

这也是为什么“存快照”不等于“整仓全量拷贝”。

3. 长期存储会打包压缩

git gc 会把对象重新打包,形成 packfile。打包后 Git 内部会进一步做压缩,很多对象之间还会利用差异编码节省空间。

所以 Git 的策略更像:

  • 日常写入:对象化、简单、快速
  • 长期存储:打包、压缩、节省空间

Git 仓库里的常见对象

常见核心对象有四类:

对象 存什么 可以把它想成
blob 文件内容 一张纸,只管内容,不管文件名
tree 目录结构 一个文件夹目录表
commit 提交元信息 一张记录“谁在什么时候提交了什么目录树”的卡片
tag 标签对象(常见于 annotated tag) 给某个对象贴上的正式标签

三个核心对象怎么串起来

commit
  └─ 指向 tree
       ├─ 指向 blob(文件内容)
       └─ 指向子 tree(子目录)

也就是说:

  • blob 不知道自己叫什么名字
  • 文件名和目录层级由 tree
  • 某次提交最终指向的是一棵目录树

commit 历史为什么是 DAG

Git 提交历史通常被描述为 DAG(有向无环图)。

概念 含义
有向 提交之间有父子指向关系
无环 提交不会形成回路
整个历史可以看成节点和边组成的结构

这里的“有向”更准确地表示 父子关系方向,而不是单纯“时间箭头”。提交时间和提交关系常常相关,但不是完全等价的概念。

分支为什么这么轻

因为分支本质上只是“一个指向提交的名字”。

main    -> C4
feature -> C3

创建分支通常不是复制整份代码,而是多了一个新的引用指向已有提交。

工作区、暂存区、提交之间的关系

理解 Git 最好别只背命令,还要建立这条链路:

工作区 -> 暂存区 -> commit -> 对象库
  • 工作区:你眼前正在编辑的文件
  • 暂存区:准备纳入下一次提交的快照内容
  • commit:一次正式提交记录
  • 对象库:Git 最终存储对象的地方

一个常见误区

很多人听到“Git 存快照”,就以为:

每次提交都把每个文件重新完整复制一次。

这是不准确的。Git 记录的是“目录树在这一刻长什么样”,然后通过对象复用和打包压缩,把成本控制在可接受范围内。

一句话总结

Git 的“快照”本质上是对目录树状态的记录,而不是对每次编辑动作的线性录像;它靠对象复用和打包压缩,兼顾了历史读取效率与存储空间。

相关问题

  • SHA-1 是什么? → 是内容哈希,Git 用它给对象做标识与完整性校验;现代版本也在逐步支持更强哈希算法。
  • 为什么文件改名后有时 Git 还能识别历史? → 因为 Git 更关注内容相似度,而不是只看文件名。
  • PR 和 MR 有区别吗? → 名称不同,本质上都是“请求把一个分支合并到另一个分支”。

技术拓展

Git Flow 和 Trunk Based 怎么看

分支工作流本质上是在回答一个问题:

团队希望把“开发中的不稳定变化”与“可发布主线”隔离到什么程度?

  • Git Flow:分支层次更多,发布节奏更明显
  • Trunk Based:主干更短平快,更依赖持续集成和自动化测试

两者没有绝对优劣,关键看团队的协作习惯和工程能力。

Learning Note

本文为个人学习记录,主要来自与 AI 对话后的知识整理与实践总结,仅供个人学习参考。