Git 原理详解

Git 原理详解

1. Git 的本质

Git 的官方定义是"分布式版本控制系统",但 Linus 本人说过一句话:

Git 核心是一个内容寻址文件系统,版本控制只是在这个文件系统上构建的应用。

这句话是理解 Git 一切行为的钥匙。

快照 vs 差异

SVN 记录的是"每次改了什么"------存储文件之间的差异(delta)。Git 记录的是"每次长什么样"------存储整个项目的完整快照。
#mermaid-svg-K9T4g538DoHdRJ8e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-K9T4g538DoHdRJ8e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-K9T4g538DoHdRJ8e .error-icon{fill:#552222;}#mermaid-svg-K9T4g538DoHdRJ8e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K9T4g538DoHdRJ8e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K9T4g538DoHdRJ8e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K9T4g538DoHdRJ8e .marker.cross{stroke:#333333;}#mermaid-svg-K9T4g538DoHdRJ8e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K9T4g538DoHdRJ8e p{margin:0;}#mermaid-svg-K9T4g538DoHdRJ8e .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-K9T4g538DoHdRJ8e .cluster-label text{fill:#333;}#mermaid-svg-K9T4g538DoHdRJ8e .cluster-label span{color:#333;}#mermaid-svg-K9T4g538DoHdRJ8e .cluster-label span p{background-color:transparent;}#mermaid-svg-K9T4g538DoHdRJ8e .label text,#mermaid-svg-K9T4g538DoHdRJ8e span{fill:#333;color:#333;}#mermaid-svg-K9T4g538DoHdRJ8e .node rect,#mermaid-svg-K9T4g538DoHdRJ8e .node circle,#mermaid-svg-K9T4g538DoHdRJ8e .node ellipse,#mermaid-svg-K9T4g538DoHdRJ8e .node polygon,#mermaid-svg-K9T4g538DoHdRJ8e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-K9T4g538DoHdRJ8e .rough-node .label text,#mermaid-svg-K9T4g538DoHdRJ8e .node .label text,#mermaid-svg-K9T4g538DoHdRJ8e .image-shape .label,#mermaid-svg-K9T4g538DoHdRJ8e .icon-shape .label{text-anchor:middle;}#mermaid-svg-K9T4g538DoHdRJ8e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-K9T4g538DoHdRJ8e .rough-node .label,#mermaid-svg-K9T4g538DoHdRJ8e .node .label,#mermaid-svg-K9T4g538DoHdRJ8e .image-shape .label,#mermaid-svg-K9T4g538DoHdRJ8e .icon-shape .label{text-align:center;}#mermaid-svg-K9T4g538DoHdRJ8e .node.clickable{cursor:pointer;}#mermaid-svg-K9T4g538DoHdRJ8e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-K9T4g538DoHdRJ8e .arrowheadPath{fill:#333333;}#mermaid-svg-K9T4g538DoHdRJ8e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-K9T4g538DoHdRJ8e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-K9T4g538DoHdRJ8e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K9T4g538DoHdRJ8e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-K9T4g538DoHdRJ8e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K9T4g538DoHdRJ8e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-K9T4g538DoHdRJ8e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-K9T4g538DoHdRJ8e .cluster text{fill:#333;}#mermaid-svg-K9T4g538DoHdRJ8e .cluster span{color:#333;}#mermaid-svg-K9T4g538DoHdRJ8e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-K9T4g538DoHdRJ8e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-K9T4g538DoHdRJ8e rect.text{fill:none;stroke-width:0;}#mermaid-svg-K9T4g538DoHdRJ8e .icon-shape,#mermaid-svg-K9T4g538DoHdRJ8e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K9T4g538DoHdRJ8e .icon-shape p,#mermaid-svg-K9T4g538DoHdRJ8e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-K9T4g538DoHdRJ8e .icon-shape .label rect,#mermaid-svg-K9T4g538DoHdRJ8e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K9T4g538DoHdRJ8e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-K9T4g538DoHdRJ8e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-K9T4g538DoHdRJ8e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SVN:差异存储
版本1: 完整文件
+2行
版本2: 需从V1+D1计算
+3行
版本3: 需从V1+D1+D2计算
#mermaid-svg-kWhYaM9djNZGw5Ey{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kWhYaM9djNZGw5Ey .error-icon{fill:#552222;}#mermaid-svg-kWhYaM9djNZGw5Ey .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kWhYaM9djNZGw5Ey .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kWhYaM9djNZGw5Ey .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kWhYaM9djNZGw5Ey .marker.cross{stroke:#333333;}#mermaid-svg-kWhYaM9djNZGw5Ey svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kWhYaM9djNZGw5Ey p{margin:0;}#mermaid-svg-kWhYaM9djNZGw5Ey .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster-label text{fill:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster-label span{color:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster-label span p{background-color:transparent;}#mermaid-svg-kWhYaM9djNZGw5Ey .label text,#mermaid-svg-kWhYaM9djNZGw5Ey span{fill:#333;color:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey .node rect,#mermaid-svg-kWhYaM9djNZGw5Ey .node circle,#mermaid-svg-kWhYaM9djNZGw5Ey .node ellipse,#mermaid-svg-kWhYaM9djNZGw5Ey .node polygon,#mermaid-svg-kWhYaM9djNZGw5Ey .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kWhYaM9djNZGw5Ey .rough-node .label text,#mermaid-svg-kWhYaM9djNZGw5Ey .node .label text,#mermaid-svg-kWhYaM9djNZGw5Ey .image-shape .label,#mermaid-svg-kWhYaM9djNZGw5Ey .icon-shape .label{text-anchor:middle;}#mermaid-svg-kWhYaM9djNZGw5Ey .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kWhYaM9djNZGw5Ey .rough-node .label,#mermaid-svg-kWhYaM9djNZGw5Ey .node .label,#mermaid-svg-kWhYaM9djNZGw5Ey .image-shape .label,#mermaid-svg-kWhYaM9djNZGw5Ey .icon-shape .label{text-align:center;}#mermaid-svg-kWhYaM9djNZGw5Ey .node.clickable{cursor:pointer;}#mermaid-svg-kWhYaM9djNZGw5Ey .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kWhYaM9djNZGw5Ey .arrowheadPath{fill:#333333;}#mermaid-svg-kWhYaM9djNZGw5Ey .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kWhYaM9djNZGw5Ey .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kWhYaM9djNZGw5Ey .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kWhYaM9djNZGw5Ey .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kWhYaM9djNZGw5Ey .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kWhYaM9djNZGw5Ey .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster text{fill:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey .cluster span{color:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kWhYaM9djNZGw5Ey .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kWhYaM9djNZGw5Ey rect.text{fill:none;stroke-width:0;}#mermaid-svg-kWhYaM9djNZGw5Ey .icon-shape,#mermaid-svg-kWhYaM9djNZGw5Ey .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kWhYaM9djNZGw5Ey .icon-shape p,#mermaid-svg-kWhYaM9djNZGw5Ey .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kWhYaM9djNZGw5Ey .icon-shape .label rect,#mermaid-svg-kWhYaM9djNZGw5Ey .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kWhYaM9djNZGw5Ey .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kWhYaM9djNZGw5Ey .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kWhYaM9djNZGw5Ey :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Git:快照存储
快照1: 完整状态
快照2: 完整状态
快照3: 完整状态

SVN Git
存储方式 差异链 完整快照
读任意版本 从头回放差异链 直接取快照,O(1)
分支成本 复制目录 移动指针
离线工作 不可能 天然支持

Git 并非真的每次都存全量------Pack 文件中的 delta 压缩会在后台优化存储空间。但这是存储优化 ,不是数据模型。从逻辑模型上看,每个 commit 就是一张完整快照。

2. .git 目录解剖

git init 做的唯一一件事:创建 .git 目录。

复制代码
.git/
├── HEAD          ← 你当前在哪
├── config        ← 仓库级配置
├── index         ← 暂存区(二进制文件)
├── objects/      ← 所有对象存储
│   ├── pack/     ← 压缩后的 pack 文件
│   └── ab/       ← 松散对象(SHA-1 前2位作目录,后38位作文件名)
├── refs/         ← 所有引用(指针)
│   ├── heads/    ← 分支指针
│   ├── tags/     ← 标签指针
│   └── remotes/  ← 远程分支指针
└── logs/         ← reflog 操作日志

关键认知:这个目录就是 Git 的全部。删掉它,仓库消失;复制它,仓库完整迁移。Git 没有数据库、没有服务进程、没有守护线程,所有数据都在这个目录里。

3. 四种对象

Git 用 SHA-1 哈希作为对象的唯一标识。所有内容------文件、目录、提交、标签------都存储为对象。一共四种:

blob:文件内容

blob 只存储文件内容,不存储文件名、不存储权限。

复制代码
文件 hello.txt 内容为 "hello world"
→ SHA-1 = 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
→ 存储为 objects/3b/18e512...

同一个内容只存一份 。无论文件叫 hello.txt 还是 greeting.md,只要内容是 "hello world",SHA-1 相同,指向同一个 blob。

tree:目录结构

tree 存储目录的文件名 + 权限 + blob/tree 引用,相当于一个目录清单。

复制代码
tree 对象内容:
├── 100644 blob 3b18e51...  hello.txt
├── 100644 blob a82e6d2...  README.md
└── 040000 tree 4b6692a...  src/

tree 可以引用 blob(文件)也可以引用 tree(子目录),形成树状结构。

commit:快照元数据

commit 指向一个 tree(项目根目录快照),并记录元数据:

复制代码
commit 对象内容:
├── tree      4b6692a...     ← 项目根目录的 tree
├── parent    2f3a7c1...     ← 上一个 commit(可有0个、1个或2个)
├── author    Kim <kim@example.com> 2026-06-24
├── committer Kim <kim@example.com> 2026-06-24
└── message   "fix: 修复登录bug"

parent 指针形成链表------这就是提交历史。merge commit 有两个 parent。

tag: annotated tag

git tag -a v1.0 会创建一个 tag 对象,指向某个 commit,并附上标签信息(打标签者、日期、附注)。

轻量标签(git tag v1.0)不创建对象,只在 refs/tags/ 下放一个指向 commit 的引用。

四种对象的关系

#mermaid-svg-QL22dM2FlyrU07LE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QL22dM2FlyrU07LE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QL22dM2FlyrU07LE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QL22dM2FlyrU07LE .error-icon{fill:#552222;}#mermaid-svg-QL22dM2FlyrU07LE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QL22dM2FlyrU07LE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QL22dM2FlyrU07LE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QL22dM2FlyrU07LE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QL22dM2FlyrU07LE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QL22dM2FlyrU07LE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QL22dM2FlyrU07LE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QL22dM2FlyrU07LE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QL22dM2FlyrU07LE .marker.cross{stroke:#333333;}#mermaid-svg-QL22dM2FlyrU07LE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QL22dM2FlyrU07LE p{margin:0;}#mermaid-svg-QL22dM2FlyrU07LE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QL22dM2FlyrU07LE .cluster-label text{fill:#333;}#mermaid-svg-QL22dM2FlyrU07LE .cluster-label span{color:#333;}#mermaid-svg-QL22dM2FlyrU07LE .cluster-label span p{background-color:transparent;}#mermaid-svg-QL22dM2FlyrU07LE .label text,#mermaid-svg-QL22dM2FlyrU07LE span{fill:#333;color:#333;}#mermaid-svg-QL22dM2FlyrU07LE .node rect,#mermaid-svg-QL22dM2FlyrU07LE .node circle,#mermaid-svg-QL22dM2FlyrU07LE .node ellipse,#mermaid-svg-QL22dM2FlyrU07LE .node polygon,#mermaid-svg-QL22dM2FlyrU07LE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QL22dM2FlyrU07LE .rough-node .label text,#mermaid-svg-QL22dM2FlyrU07LE .node .label text,#mermaid-svg-QL22dM2FlyrU07LE .image-shape .label,#mermaid-svg-QL22dM2FlyrU07LE .icon-shape .label{text-anchor:middle;}#mermaid-svg-QL22dM2FlyrU07LE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QL22dM2FlyrU07LE .rough-node .label,#mermaid-svg-QL22dM2FlyrU07LE .node .label,#mermaid-svg-QL22dM2FlyrU07LE .image-shape .label,#mermaid-svg-QL22dM2FlyrU07LE .icon-shape .label{text-align:center;}#mermaid-svg-QL22dM2FlyrU07LE .node.clickable{cursor:pointer;}#mermaid-svg-QL22dM2FlyrU07LE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QL22dM2FlyrU07LE .arrowheadPath{fill:#333333;}#mermaid-svg-QL22dM2FlyrU07LE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QL22dM2FlyrU07LE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QL22dM2FlyrU07LE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QL22dM2FlyrU07LE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QL22dM2FlyrU07LE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QL22dM2FlyrU07LE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QL22dM2FlyrU07LE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QL22dM2FlyrU07LE .cluster text{fill:#333;}#mermaid-svg-QL22dM2FlyrU07LE .cluster span{color:#333;}#mermaid-svg-QL22dM2FlyrU07LE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QL22dM2FlyrU07LE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QL22dM2FlyrU07LE rect.text{fill:none;stroke-width:0;}#mermaid-svg-QL22dM2FlyrU07LE .icon-shape,#mermaid-svg-QL22dM2FlyrU07LE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QL22dM2FlyrU07LE .icon-shape p,#mermaid-svg-QL22dM2FlyrU07LE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QL22dM2FlyrU07LE .icon-shape .label rect,#mermaid-svg-QL22dM2FlyrU07LE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QL22dM2FlyrU07LE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QL22dM2FlyrU07LE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QL22dM2FlyrU07LE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} commit

元数据 + 指向 tree
tree (根目录)

文件名 + 引用
blob

文件内容
tree (子目录)

文件名 + 引用
blob

文件内容
parent commit

提交历史链
tag

标签名 + 指向 commit

4. 对象存储机制

一个对象从写入到落盘的过程:

复制代码
1. 构造内容:blob + 空格 + 内容字节数 + \0 + 实际内容
   例:blob 11\0hello world

2. SHA-1 哈希:对上述整体计算
   → 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

3. zlib 压缩:将原始内容用 zlib 压缩

4. 写入文件:objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad

这个机制保证了:

  • 内容寻址:相同内容必然产生相同哈希,天然去重
  • 不可篡改:改一个字节,哈希全变,引用全部失效
  • 完整性校验 :任何时候可以用 git fsck 扫描全部对象验证完整性

5. 暂存区(index)

暂存区是 Git 最容易被误解的概念。

index 不是 objects 中的对象,而是 .git/index 这个独立的二进制文件。它是一张登记表,记录"下一次 commit 要包含哪些文件的哪个版本"。

三棵树

Git 的核心工作流就是三棵树之间的同步:
#mermaid-svg-GHXr1LNA4vob9hjI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GHXr1LNA4vob9hjI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GHXr1LNA4vob9hjI .error-icon{fill:#552222;}#mermaid-svg-GHXr1LNA4vob9hjI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GHXr1LNA4vob9hjI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GHXr1LNA4vob9hjI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GHXr1LNA4vob9hjI .marker.cross{stroke:#333333;}#mermaid-svg-GHXr1LNA4vob9hjI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GHXr1LNA4vob9hjI p{margin:0;}#mermaid-svg-GHXr1LNA4vob9hjI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GHXr1LNA4vob9hjI .cluster-label text{fill:#333;}#mermaid-svg-GHXr1LNA4vob9hjI .cluster-label span{color:#333;}#mermaid-svg-GHXr1LNA4vob9hjI .cluster-label span p{background-color:transparent;}#mermaid-svg-GHXr1LNA4vob9hjI .label text,#mermaid-svg-GHXr1LNA4vob9hjI span{fill:#333;color:#333;}#mermaid-svg-GHXr1LNA4vob9hjI .node rect,#mermaid-svg-GHXr1LNA4vob9hjI .node circle,#mermaid-svg-GHXr1LNA4vob9hjI .node ellipse,#mermaid-svg-GHXr1LNA4vob9hjI .node polygon,#mermaid-svg-GHXr1LNA4vob9hjI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GHXr1LNA4vob9hjI .rough-node .label text,#mermaid-svg-GHXr1LNA4vob9hjI .node .label text,#mermaid-svg-GHXr1LNA4vob9hjI .image-shape .label,#mermaid-svg-GHXr1LNA4vob9hjI .icon-shape .label{text-anchor:middle;}#mermaid-svg-GHXr1LNA4vob9hjI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GHXr1LNA4vob9hjI .rough-node .label,#mermaid-svg-GHXr1LNA4vob9hjI .node .label,#mermaid-svg-GHXr1LNA4vob9hjI .image-shape .label,#mermaid-svg-GHXr1LNA4vob9hjI .icon-shape .label{text-align:center;}#mermaid-svg-GHXr1LNA4vob9hjI .node.clickable{cursor:pointer;}#mermaid-svg-GHXr1LNA4vob9hjI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GHXr1LNA4vob9hjI .arrowheadPath{fill:#333333;}#mermaid-svg-GHXr1LNA4vob9hjI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GHXr1LNA4vob9hjI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GHXr1LNA4vob9hjI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GHXr1LNA4vob9hjI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GHXr1LNA4vob9hjI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GHXr1LNA4vob9hjI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GHXr1LNA4vob9hjI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GHXr1LNA4vob9hjI .cluster text{fill:#333;}#mermaid-svg-GHXr1LNA4vob9hjI .cluster span{color:#333;}#mermaid-svg-GHXr1LNA4vob9hjI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GHXr1LNA4vob9hjI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GHXr1LNA4vob9hjI rect.text{fill:none;stroke-width:0;}#mermaid-svg-GHXr1LNA4vob9hjI .icon-shape,#mermaid-svg-GHXr1LNA4vob9hjI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GHXr1LNA4vob9hjI .icon-shape p,#mermaid-svg-GHXr1LNA4vob9hjI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GHXr1LNA4vob9hjI .icon-shape .label rect,#mermaid-svg-GHXr1LNA4vob9hjI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GHXr1LNA4vob9hjI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GHXr1LNA4vob9hjI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GHXr1LNA4vob9hjI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} git add
git commit
git checkout
git reset
工作区

实际文件
暂存区

index 登记表
版本库

objects + refs

命令 源 → 目标
git add 工作区 → 暂存区
git commit 暂存区 → 版本库
git diff 工作区 vs 暂存区
git diff --cached 暂存区 vs 版本库
git diff HEAD 工作区 vs 版本库

git status 的本质:比较这三棵树,告诉你哪里不一致。

git add 做了什么

复制代码
1. 读取工作区文件内容
2. 计算 SHA-1,用 zlib 压缩后写入 objects/(如果已存在则跳过)
3. 更新 index 登记表:记录文件路径 → blob SHA-1 的映射

文件内容进入 objects,文件名留在 index------这就是 blob 不存文件名的原因:文件名是 tree/index 的职责。

6. 分支的本质

分支可能是 Git 最优雅的设计:分支只是一个文件,内容是 40 字节的 SHA-1

复制代码
.git/refs/heads/main    → 2f3a7c1e8d4b5a6f9e0c1d2b3a4f5e6d7c8b9a0e
.git/refs/heads/dev     → 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b

创建分支 = 写一个文件。删除分支 = 删一个文件。切换分支 = 改 HEAD 指向。全部操作都是 O(1),无论仓库多大、历史多长。

HEAD 是当前所在位置的指针,通常是符号引用------指向某个分支名:

复制代码
HEAD → refs/heads/main → 2f3a7c1...

git checkout main:HEAD → refs/heads/main

git checkout dev:HEAD → refs/heads/dev

detached HEAD

当 HEAD 直接指向某个 commit 而不是分支名时:

复制代码
HEAD → 2f3a7c1...(直接指向 commit,没有分支名做中介)

此时提交的新 commit 没有分支引用指向它,切换走后可能被 GC 回收。这就是 detached HEAD 的风险。

7. 合并原理

fast-forward

当目标分支是当前分支的直接后继,Git 只需移动指针:
#mermaid-svg-aapkzWtfRWF0riLs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aapkzWtfRWF0riLs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aapkzWtfRWF0riLs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aapkzWtfRWF0riLs .error-icon{fill:#552222;}#mermaid-svg-aapkzWtfRWF0riLs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aapkzWtfRWF0riLs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aapkzWtfRWF0riLs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aapkzWtfRWF0riLs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aapkzWtfRWF0riLs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aapkzWtfRWF0riLs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aapkzWtfRWF0riLs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aapkzWtfRWF0riLs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aapkzWtfRWF0riLs .marker.cross{stroke:#333333;}#mermaid-svg-aapkzWtfRWF0riLs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aapkzWtfRWF0riLs p{margin:0;}#mermaid-svg-aapkzWtfRWF0riLs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aapkzWtfRWF0riLs .cluster-label text{fill:#333;}#mermaid-svg-aapkzWtfRWF0riLs .cluster-label span{color:#333;}#mermaid-svg-aapkzWtfRWF0riLs .cluster-label span p{background-color:transparent;}#mermaid-svg-aapkzWtfRWF0riLs .label text,#mermaid-svg-aapkzWtfRWF0riLs span{fill:#333;color:#333;}#mermaid-svg-aapkzWtfRWF0riLs .node rect,#mermaid-svg-aapkzWtfRWF0riLs .node circle,#mermaid-svg-aapkzWtfRWF0riLs .node ellipse,#mermaid-svg-aapkzWtfRWF0riLs .node polygon,#mermaid-svg-aapkzWtfRWF0riLs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aapkzWtfRWF0riLs .rough-node .label text,#mermaid-svg-aapkzWtfRWF0riLs .node .label text,#mermaid-svg-aapkzWtfRWF0riLs .image-shape .label,#mermaid-svg-aapkzWtfRWF0riLs .icon-shape .label{text-anchor:middle;}#mermaid-svg-aapkzWtfRWF0riLs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aapkzWtfRWF0riLs .rough-node .label,#mermaid-svg-aapkzWtfRWF0riLs .node .label,#mermaid-svg-aapkzWtfRWF0riLs .image-shape .label,#mermaid-svg-aapkzWtfRWF0riLs .icon-shape .label{text-align:center;}#mermaid-svg-aapkzWtfRWF0riLs .node.clickable{cursor:pointer;}#mermaid-svg-aapkzWtfRWF0riLs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aapkzWtfRWF0riLs .arrowheadPath{fill:#333333;}#mermaid-svg-aapkzWtfRWF0riLs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aapkzWtfRWF0riLs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aapkzWtfRWF0riLs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aapkzWtfRWF0riLs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aapkzWtfRWF0riLs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aapkzWtfRWF0riLs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aapkzWtfRWF0riLs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aapkzWtfRWF0riLs .cluster text{fill:#333;}#mermaid-svg-aapkzWtfRWF0riLs .cluster span{color:#333;}#mermaid-svg-aapkzWtfRWF0riLs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aapkzWtfRWF0riLs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aapkzWtfRWF0riLs rect.text{fill:none;stroke-width:0;}#mermaid-svg-aapkzWtfRWF0riLs .icon-shape,#mermaid-svg-aapkzWtfRWF0riLs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aapkzWtfRWF0riLs .icon-shape p,#mermaid-svg-aapkzWtfRWF0riLs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aapkzWtfRWF0riLs .icon-shape .label rect,#mermaid-svg-aapkzWtfRWF0riLs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aapkzWtfRWF0riLs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aapkzWtfRWF0riLs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aapkzWtfRWF0riLs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 合并前
main: C1 → C2
dev: C1 → C2 → C3
#mermaid-svg-oseFQNcFFy4oiiSA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oseFQNcFFy4oiiSA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oseFQNcFFy4oiiSA .error-icon{fill:#552222;}#mermaid-svg-oseFQNcFFy4oiiSA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oseFQNcFFy4oiiSA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oseFQNcFFy4oiiSA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oseFQNcFFy4oiiSA .marker.cross{stroke:#333333;}#mermaid-svg-oseFQNcFFy4oiiSA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oseFQNcFFy4oiiSA p{margin:0;}#mermaid-svg-oseFQNcFFy4oiiSA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oseFQNcFFy4oiiSA .cluster-label text{fill:#333;}#mermaid-svg-oseFQNcFFy4oiiSA .cluster-label span{color:#333;}#mermaid-svg-oseFQNcFFy4oiiSA .cluster-label span p{background-color:transparent;}#mermaid-svg-oseFQNcFFy4oiiSA .label text,#mermaid-svg-oseFQNcFFy4oiiSA span{fill:#333;color:#333;}#mermaid-svg-oseFQNcFFy4oiiSA .node rect,#mermaid-svg-oseFQNcFFy4oiiSA .node circle,#mermaid-svg-oseFQNcFFy4oiiSA .node ellipse,#mermaid-svg-oseFQNcFFy4oiiSA .node polygon,#mermaid-svg-oseFQNcFFy4oiiSA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oseFQNcFFy4oiiSA .rough-node .label text,#mermaid-svg-oseFQNcFFy4oiiSA .node .label text,#mermaid-svg-oseFQNcFFy4oiiSA .image-shape .label,#mermaid-svg-oseFQNcFFy4oiiSA .icon-shape .label{text-anchor:middle;}#mermaid-svg-oseFQNcFFy4oiiSA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oseFQNcFFy4oiiSA .rough-node .label,#mermaid-svg-oseFQNcFFy4oiiSA .node .label,#mermaid-svg-oseFQNcFFy4oiiSA .image-shape .label,#mermaid-svg-oseFQNcFFy4oiiSA .icon-shape .label{text-align:center;}#mermaid-svg-oseFQNcFFy4oiiSA .node.clickable{cursor:pointer;}#mermaid-svg-oseFQNcFFy4oiiSA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oseFQNcFFy4oiiSA .arrowheadPath{fill:#333333;}#mermaid-svg-oseFQNcFFy4oiiSA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oseFQNcFFy4oiiSA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oseFQNcFFy4oiiSA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oseFQNcFFy4oiiSA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oseFQNcFFy4oiiSA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oseFQNcFFy4oiiSA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oseFQNcFFy4oiiSA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oseFQNcFFy4oiiSA .cluster text{fill:#333;}#mermaid-svg-oseFQNcFFy4oiiSA .cluster span{color:#333;}#mermaid-svg-oseFQNcFFy4oiiSA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oseFQNcFFy4oiiSA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oseFQNcFFy4oiiSA rect.text{fill:none;stroke-width:0;}#mermaid-svg-oseFQNcFFy4oiiSA .icon-shape,#mermaid-svg-oseFQNcFFy4oiiSA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oseFQNcFFy4oiiSA .icon-shape p,#mermaid-svg-oseFQNcFFy4oiiSA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oseFQNcFFy4oiiSA .icon-shape .label rect,#mermaid-svg-oseFQNcFFy4oiiSA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oseFQNcFFy4oiiSA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oseFQNcFFy4oiiSA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oseFQNcFFy4oiiSA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 合并后
main: C1 → C2 → C3

main 指针直接移动到 C3,不产生新 commit。

三方合并

当两个分支各有新 commit 时:
#mermaid-svg-WyYltTdOMGMaSZeA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WyYltTdOMGMaSZeA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WyYltTdOMGMaSZeA .error-icon{fill:#552222;}#mermaid-svg-WyYltTdOMGMaSZeA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WyYltTdOMGMaSZeA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WyYltTdOMGMaSZeA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WyYltTdOMGMaSZeA .marker.cross{stroke:#333333;}#mermaid-svg-WyYltTdOMGMaSZeA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WyYltTdOMGMaSZeA p{margin:0;}#mermaid-svg-WyYltTdOMGMaSZeA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WyYltTdOMGMaSZeA .cluster-label text{fill:#333;}#mermaid-svg-WyYltTdOMGMaSZeA .cluster-label span{color:#333;}#mermaid-svg-WyYltTdOMGMaSZeA .cluster-label span p{background-color:transparent;}#mermaid-svg-WyYltTdOMGMaSZeA .label text,#mermaid-svg-WyYltTdOMGMaSZeA span{fill:#333;color:#333;}#mermaid-svg-WyYltTdOMGMaSZeA .node rect,#mermaid-svg-WyYltTdOMGMaSZeA .node circle,#mermaid-svg-WyYltTdOMGMaSZeA .node ellipse,#mermaid-svg-WyYltTdOMGMaSZeA .node polygon,#mermaid-svg-WyYltTdOMGMaSZeA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WyYltTdOMGMaSZeA .rough-node .label text,#mermaid-svg-WyYltTdOMGMaSZeA .node .label text,#mermaid-svg-WyYltTdOMGMaSZeA .image-shape .label,#mermaid-svg-WyYltTdOMGMaSZeA .icon-shape .label{text-anchor:middle;}#mermaid-svg-WyYltTdOMGMaSZeA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WyYltTdOMGMaSZeA .rough-node .label,#mermaid-svg-WyYltTdOMGMaSZeA .node .label,#mermaid-svg-WyYltTdOMGMaSZeA .image-shape .label,#mermaid-svg-WyYltTdOMGMaSZeA .icon-shape .label{text-align:center;}#mermaid-svg-WyYltTdOMGMaSZeA .node.clickable{cursor:pointer;}#mermaid-svg-WyYltTdOMGMaSZeA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WyYltTdOMGMaSZeA .arrowheadPath{fill:#333333;}#mermaid-svg-WyYltTdOMGMaSZeA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WyYltTdOMGMaSZeA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WyYltTdOMGMaSZeA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WyYltTdOMGMaSZeA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WyYltTdOMGMaSZeA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WyYltTdOMGMaSZeA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WyYltTdOMGMaSZeA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WyYltTdOMGMaSZeA .cluster text{fill:#333;}#mermaid-svg-WyYltTdOMGMaSZeA .cluster span{color:#333;}#mermaid-svg-WyYltTdOMGMaSZeA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WyYltTdOMGMaSZeA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WyYltTdOMGMaSZeA rect.text{fill:none;stroke-width:0;}#mermaid-svg-WyYltTdOMGMaSZeA .icon-shape,#mermaid-svg-WyYltTdOMGMaSZeA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WyYltTdOMGMaSZeA .icon-shape p,#mermaid-svg-WyYltTdOMGMaSZeA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WyYltTdOMGMaSZeA .icon-shape .label rect,#mermaid-svg-WyYltTdOMGMaSZeA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WyYltTdOMGMaSZeA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WyYltTdOMGMaSZeA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WyYltTdOMGMaSZeA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} C3 (main)
C1 (共同祖先)
C4 (dev)
C5 (merge commit)

双 parent: C3 + C4

  1. 找到两个分支的最近共同祖先(merge base)
  2. 对两个分支分别与 merge base 做 diff
  3. 同一处只在一方修改 → 自动采用
  4. 同一处双方都修改 → 冲突,需人工解决
  5. 生成 merge commit,两个 parent 指针

三方合并的关键:不是直接比较两个分支的差异,而是以共同祖先为基准分别比较。这样才能判断"哪边改了、哪边没改"。

8. Pack 文件与 GC

松散对象的问题

每次 git add 都生成一个松散对象文件。大量小文件浪费 inode、降低性能。

Pack 压缩

git gc 将松散对象打包为 pack 文件,核心是 delta 编码

复制代码
松散对象:
  blob A: "hello world"          (独立存储)
  blob B: "hello world!!"        (独立存储)

Pack 中:
  blob A: "hello world"          (完整存储,作为 base)
  blob B: delta(A, "+!!")        (只存差异)

Pack 不是简单的整包压缩,而是智能选择 base 对象,对相似内容做 delta 编码。选择策略:文件名相近、内容相似的对象优先作为 base-delta 对。

GC 的可达性判断

Git 用可达性分析判断哪些对象可以丢弃:

  1. 从所有引用(分支、标签、reflog)出发
  2. 沿 commit → tree → blob 链遍历
  3. 能到达的对象保留,到达不了的丢弃

reflog 的保护作用:即使你删了分支、reset 了 commit,reflog 中仍保留指向这些 commit 的引用,使得它们"可达"而不会被 GC。默认保留 90 天。这就是为什么 git reflog 能救回"丢失"的提交。

9. 常用命令的原理映射

理解了对象模型后,常用命令的本质一目了然:

命令 本质操作
git add file hash-object 写 blob + update-index 更新 index
git commit write-tree 将 index 转为 tree + commit-tree 生成 commit + update-ref 移动分支指针
git reset --soft HEAD~1 只移动分支指针,index 和工作区不动
git reset --mixed HEAD~1 移动分支指针 + 重置 index,工作区不动
git reset --hard HEAD~1 移动分支指针 + 重置 index + 重置工作区(危险)
git checkout -- file 从 index 恢复文件到工作区
git checkout branch 移动 HEAD + 用目标 commit 的 tree 更新 index 和工作区
git rebase main 逐个 cherry-pick 当前分支的 commit 到 main 末端,生成新 commit(SHA-1 全变)
git cherry-pick C3 将 C3 的变更在当前 HEAD 上重放,生成新 commit
git stash 生成特殊 commit(无分支引用指向),用 reflog 保护

reset 三种模式的区别,本质就是三棵树同步到哪一步
#mermaid-svg-PNqHjSW7clocpMpi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PNqHjSW7clocpMpi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PNqHjSW7clocpMpi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PNqHjSW7clocpMpi .error-icon{fill:#552222;}#mermaid-svg-PNqHjSW7clocpMpi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PNqHjSW7clocpMpi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PNqHjSW7clocpMpi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PNqHjSW7clocpMpi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PNqHjSW7clocpMpi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PNqHjSW7clocpMpi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PNqHjSW7clocpMpi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PNqHjSW7clocpMpi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PNqHjSW7clocpMpi .marker.cross{stroke:#333333;}#mermaid-svg-PNqHjSW7clocpMpi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PNqHjSW7clocpMpi p{margin:0;}#mermaid-svg-PNqHjSW7clocpMpi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PNqHjSW7clocpMpi .cluster-label text{fill:#333;}#mermaid-svg-PNqHjSW7clocpMpi .cluster-label span{color:#333;}#mermaid-svg-PNqHjSW7clocpMpi .cluster-label span p{background-color:transparent;}#mermaid-svg-PNqHjSW7clocpMpi .label text,#mermaid-svg-PNqHjSW7clocpMpi span{fill:#333;color:#333;}#mermaid-svg-PNqHjSW7clocpMpi .node rect,#mermaid-svg-PNqHjSW7clocpMpi .node circle,#mermaid-svg-PNqHjSW7clocpMpi .node ellipse,#mermaid-svg-PNqHjSW7clocpMpi .node polygon,#mermaid-svg-PNqHjSW7clocpMpi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PNqHjSW7clocpMpi .rough-node .label text,#mermaid-svg-PNqHjSW7clocpMpi .node .label text,#mermaid-svg-PNqHjSW7clocpMpi .image-shape .label,#mermaid-svg-PNqHjSW7clocpMpi .icon-shape .label{text-anchor:middle;}#mermaid-svg-PNqHjSW7clocpMpi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PNqHjSW7clocpMpi .rough-node .label,#mermaid-svg-PNqHjSW7clocpMpi .node .label,#mermaid-svg-PNqHjSW7clocpMpi .image-shape .label,#mermaid-svg-PNqHjSW7clocpMpi .icon-shape .label{text-align:center;}#mermaid-svg-PNqHjSW7clocpMpi .node.clickable{cursor:pointer;}#mermaid-svg-PNqHjSW7clocpMpi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PNqHjSW7clocpMpi .arrowheadPath{fill:#333333;}#mermaid-svg-PNqHjSW7clocpMpi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PNqHjSW7clocpMpi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PNqHjSW7clocpMpi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNqHjSW7clocpMpi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PNqHjSW7clocpMpi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNqHjSW7clocpMpi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PNqHjSW7clocpMpi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PNqHjSW7clocpMpi .cluster text{fill:#333;}#mermaid-svg-PNqHjSW7clocpMpi .cluster span{color:#333;}#mermaid-svg-PNqHjSW7clocpMpi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PNqHjSW7clocpMpi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PNqHjSW7clocpMpi rect.text{fill:none;stroke-width:0;}#mermaid-svg-PNqHjSW7clocpMpi .icon-shape,#mermaid-svg-PNqHjSW7clocpMpi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNqHjSW7clocpMpi .icon-shape p,#mermaid-svg-PNqHjSW7clocpMpi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PNqHjSW7clocpMpi .icon-shape .label rect,#mermaid-svg-PNqHjSW7clocpMpi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNqHjSW7clocpMpi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PNqHjSW7clocpMpi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PNqHjSW7clocpMpi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} reset: 移动分支指针
--soft: 停在这里
--mixed: 再重置 index
--hard: 再重置工作区


全文一句话总结:Git 的数据模型只有四种对象(blob/tree/commit/tag),所有命令都是在操作这些对象和指向它们的引用。理解了这个模型,Git 的每个行为都可以推导出来,不再需要死记命令。