文章目录
-
- [一、Git 命令概述](#一、Git 命令概述)
-
- [1.1 从速查表到认知框架](#1.1 从速查表到认知框架)
- [1.2 数据模型与命令分层](#1.2 数据模型与命令分层)
-
- [1.2.1 数据模型:Git 的对象图](#1.2.1 数据模型:Git 的对象图)
- [1.2.2 命令分层:Porcelain 与 Plumbing](#1.2.2 命令分层:Porcelain 与 Plumbing)
- [1.3 Git 命令的分类视角](#1.3 Git 命令的分类视角)
- [二、工作区 ⇄ 暂存区:控制进入提交的改动](#二、工作区 ⇄ 暂存区:控制进入提交的改动)
-
- [2.1 git add ------ 快照入暂存](#2.1 git add —— 快照入暂存)
- [2.2 git restore ------ 精准回滚](#2.2 git restore —— 精准回滚)
- [2.3 git stash ------ 临时搁置](#2.3 git stash —— 临时搁置)
- [三、暂存区 ⇄ 本地仓库:提交与撤销](#三、暂存区 ⇄ 本地仓库:提交与撤销)
-
- [3.1 git commit ------ 固化快照](#3.1 git commit —— 固化快照)
- [3.2 git reset ------ 移动指针的"时光机"](#3.2 git reset —— 移动指针的“时光机”)
- [3.3 git revert ------ 安全的"反向提交"](#3.3 git revert —— 安全的“反向提交”)
- [四、本地仓库内部:重组提交 DAG](#四、本地仓库内部:重组提交 DAG)
-
- [4.1 git merge ------ 保留历史的"汇合"](#4.1 git merge —— 保留历史的“汇合”)
- [4.2 git rebase ------ 重写历史的"线性化"](#4.2 git rebase —— 重写历史的“线性化”)
- [4.3 git cherry-pick ------ 精准摘取的"补丁移植"](#4.3 git cherry-pick —— 精准摘取的“补丁移植”)
- [4.4 对比总结](#4.4 对比总结)
- [五、本地 ⇄ 远程仓库:分布式同步](#五、本地 ⇄ 远程仓库:分布式同步)
-
- [5.1 git fetch ------ 只下载不合并](#5.1 git fetch —— 只下载不合并)
- [5.2 git pull ------ 传输 + 合并的快捷方式](#5.2 git pull —— 传输 + 合并的快捷方式)
- [5.3 git push ------ 上传并更新引用](#5.3 git push —— 上传并更新引用)
- 六、只读观测
-
- [6.1 git status ------ 三域状态快照](#6.1 git status —— 三域状态快照)
- [6.2 git diff ------ 差异引擎](#6.2 git diff —— 差异引擎)
- [6.3 git log ------ 历史遍历](#6.3 git log —— 历史遍历)
- [6.4 git reflog ------ 引用的"黑匣子"](#6.4 git reflog —— 引用的“黑匣子”)
- 参考资料
一、Git 命令概述
1.1 从速查表到认知框架
Git 官方提供了两类核心参考资料:
- Cheat Sheet:场景化、扁平化的命令速查表,适合快速回忆语法。
- Git Reference:按 Git 内部子系统(Setup、Snapshotting、Branching、Sharing 等)组织的完整手册,适合查阅细节。
这两类资料分别解决了"怎么用"和"是什么"的问题,但在面对复杂场景时,仍有一个关键缺口:**它们较少解释命令之间的内在关联,也难以直接映射到一个统一的用户心智模型。**例如,为什么 reset 既像撤销又像历史改写?为什么 fetch 和 pull 必须分开理解?为什么某些操作是"危险"的,而另一些是"安全"的?要回答这些问题,需要的不只是一份更长的命令列表,而是一套能够解释 Git 行为的认知框架。
本文尝试换一个视角:不再以"命令"为中心,而是以数据流向为中心。Git 的写操作本质上驱动数据在四个核心域之间流动------工作区、暂存区(索引)、本地仓库与远程仓库。基于这一模型,我们可以将常用命令重新归类,从而回答上述"为什么"的问题。
因此,本文不旨在替代 Cheat Sheet 或 Reference,而是希望为它们补充一套可解释、可推导的认知框架。如果你需要快速查阅命令语法,请优先参考 Cheat Sheet;如果你需要确认某个参数的精确含义,请以 Reference 为准;如果你希望建立对 Git 数据流动的直觉,那么本文的分类视角或许能为你节省未来大量的试错成本。
1.2 数据模型与命令分层
在真正理解命令的行为差异前,还需要两个前提:Git 的数据长什么样、以及 Git 的命令分几层。本节补上这两块,后面的分类表才有地基。
1.2.1 数据模型:Git 的对象图
Git 本质上是一个内容寻址文件系统 + 有向无环图(Directed Acyclic Graph,DAG)。所有写操作最终都在操作三类核心对象:
- Commit(提交):记录快照、作者、时间以及父节点引用
- Tree(目录树):描述目录结构与文件名的映射
- Blob(文件内容):存储文件的实际数据
命令之间的差异,仅在于操作路径、作用范围与副作用的不同。这也解释了为什么本文选择"数据流向"而非"命令功能"来分类------前者能统一描述所有命令的行为。
1.2.2 命令分层:Porcelain 与 Plumbing
Git 命令分为两层,这是理解"为什么有些命令行为反直觉"的关键:
- Porcelain(上层命令):面向用户,强调易用性
git commit,git branch,git merge - Plumbing(底层命令):面向 Git 内部,强调组合性
git cat-file,git hash-object,git update-ref
设计动机:
Git 早期就明确区分"用户界面"与"存储引擎"。上层命令是对底层操作的封装,因此:
- 同一目标可以有多种上层命令实现(
merge/rebase) - 某些上层命令会组合其他上层命令来完成复杂流程(如
pull默认等价于fetch + merge) - 上层命令最终依赖底层命令操作 Git 的对象库与引用(如
commit内部会调用write-tree、commit-tree、update-ref等)
排查复杂问题时,往往需要"透过 Porcelain 看 Plumbing"------这也是理解"危险命令"(如
reset --hard)为何危险的底层视角。
1.3 Git 命令的分类视角
基于前文所述的认知框架,本文将日常高频使用的 Git 命令划分为五类。分类的依据不是命令的功能标签,而是数据在 Git 四个核心域之间的流动方向:
- 工作区(Working Directory)
- 暂存区(Index / Staging Area)
- 本地仓库(Local Repository)
- 远程仓库(Remote Repository)
先用一张图建立整体直觉------五类命令本质上就是数据在这四层域之间的流动路径:
┌──────────────────────────────────────────────┐
│ 工作区 (Working Directory) │
└──────────────────────────────────────────────┘
│
① 工作区 ⇄ 暂存:add / restore / stash
⇅
┌──────────────────────────────────────────────┐
│ 暂存区 (Index / Staging) │
└──────────────────────────────────────────────┘
│
② 提交与撤销:commit / reset / revert
⇅
┌──────────────────────────────────────────────┐
│ 本地仓库 (Local Repository) │
│ │
│ ③ 分支与历史改写:merge / rebase / cherry-pick │
│ (DAG 重组,仅影响本地仓库内部) │
└──────────────────────────────────────────────┘
│
④ 远程协作:fetch / pull / push
(本地仓库 ⇄ 远程仓库)
⇅
┌──────────────────────────────────────────────┐
│ 远程仓库 (Remote Repository) │
└──────────────────────────────────────────────┘
── ⑤ 只读观测:status / diff / log / reflog
(不产生数据流动,贯穿所有层级)
将上述流向映射到分类表,即得到本文的整理主线:
| 分类 | 数据流向 / 性质 | 代表命令 | 核心语义 |
|---|---|---|---|
| 工作区与暂存 | 工作区 ⇄ 暂存区 | add / restore / stash |
控制"哪些改动进入下次提交" |
| 提交与撤销 | 暂存区 ⇄ 本地仓库 | commit / reset / revert |
固化历史或改写已有历史 |
| 分支与历史改写 | 移动 / 重写引用 | merge / rebase / cherry-pick |
决定提交 DAG 的形态 |
| 远程协作 | 本地仓库 ⇄ 远程仓库 | fetch / pull / push |
分布式同步,解耦传输与合并 |
| 只读观测 | 不产生数据流动 | status / diff / log / reflog |
提供可观测性,辅助所有写操作 |
说明
stash本质是将工作区 / 暂存区的改动序列化后写入本地仓库的特殊引用(refs/stash),再还原工作区,因此跨越多层域;此处归入"工作区与暂存",是为了贴合其"临时搁置改动"的使用意图。reset根据调用方式不同,可能同时影响暂存区与工作区;其"改写历史"的特性也使其在撤销场景中扮演关键角色。
后续章节将按上述分类展开介绍常用命令。如需查阅完整参数与底层行为,仍以 Git - Reference 为准。
二、工作区 ⇄ 暂存区:控制进入提交的改动
git add / git restore / git stash 的核心语义是控制"哪些改动进入下次提交"。它们只在工作区、暂存区之间移动或复制数据,不产生新的提交对象(commit),也不会改写历史。
2.1 git add ------ 快照入暂存
(1) 作用与机制
git add 将工作区文件的当前内容写入 Git 对象库(生成 Blob),并将其路径与 Hash 注册到**索引(Index / Staging Area)**中。
设计动机:
- 解耦"修改"与"提交":允许将一次修改拆分为多次逻辑提交
- 精确控制提交粒度 :只提交部分文件或部分 hunk(
-p)
(2) 数据流向
text
工作区 (Working Directory)
│
│ git add <file>
▼
暂存区 (Index / Staging Area)
│
│ git commit
▼
本地仓库 (Repository)
(3) 关键细节
- 执行
git add后,工作区文件本身不受影响。理解这一点后,我们就能明白git restore --staged <file>为什么是取消暂存,保留工作区。 - 多次对同一文件执行
git add,暂存区只会保留最后一次 add 的版本 - 即使暂存区中的快照被后续操作(如
restore --staged)覆盖,只要曾经执行过add,对应的 Blob 对象仍临时存在于.git/objects中,可通过底层命令找回
2.2 git restore ------ 精准回滚
(1) 作用与机制
git restore 用于从指定源(提交或暂存区)向指定目标(工作区或暂存区)复制文件内容。它是 Git 2.23 引入的语义化命令,旨在替代 git checkout 在文件恢复场景下的混乱用法。
设计动机:
- 消除歧义 :
checkout既切换分支又恢复文件,极易误用 - 明确意图 :
restore只负责"还原内容",不影响分支指针
(2) 典型用法对比
git restore 的行为完全由 --staged 参数和目标路径决定:
| 场景 | 命令 | 源 → 目标 | 命令含义 |
|---|---|---|---|
| 丢弃工作区改动 | git restore <file> |
HEAD → 工作区 |
把工作区里该文件的状态,恢复到与 HEAD 一致 |
| 取消暂存(保留工作区) | git restore --staged <file> |
HEAD → 暂存区 |
把暂存区(Index)里该文件的状态,恢复到与 HEAD 一致 |
| 从指定提交恢复 | git restore --source=HEAD~1 <file> |
HEAD~1 → 工作区 |
把工作区里该文件的状态,恢复到与 HEAD~1 一致 |
--staged的含义是将指定目标改为暂存区。
(3) 与 reset 的区别
restore不移动HEAD或分支引用reset会移动HEAD/ 分支指针,属于"历史改写"范畴
2.3 git stash ------ 临时搁置
(1) 作用与机制
git stash 将当前工作区和暂存区的未提交改动 保存为一个特殊的栈式提交(stash@{n}),并将工作区恢复到 HEAD 状态。
设计动机:
- 上下文切换:在不提交半成品的前提下,临时切换到其他分支
- 避免污染历史:避免为了"先切分支"而制造无意义的 WIP 提交
(2) 数据流向
text
工作区 + 暂存区
│
│ git stash
▼
refs/stash(提交对象,不属于任何分支)
│
│ git stash pop → 默认只恢复到工作区
│ git stash pop --index → 同时尝试恢复暂存区
▼
工作区(+ 可选的暂存区)
(3) 关键细节
stash本身是一个游离提交,不属于任何分支 DAGstash不会自动删除,需显式drop或popgit stash push -m "msg"可附加说明,便于后续识别
三、暂存区 ⇄ 本地仓库:提交与撤销
commit / reset / revert 操作的是暂存区 → 本地仓库的数据流动,核心差异在于是否改写已有历史。
3.1 git commit ------ 固化快照
(1) 作用与机制
git commit 根据当前索引(暂存区)的内容,依次创建 tree 对象与 commit 对象,并将当前分支引用前移。
设计动机:
- 不可变快照:一旦提交,内容不可篡改(Hash 即校验)
- 原子性:一次提交代表一个逻辑完整的变更单元
(2) 关键细节
- 提交前必须
add,否则改动不会进入新提交 commit --amend本质是替换最近一次提交(生成新 Hash)。原提交对象仍保留在对象库中,只是不再被分支引用直接指向,最终由 GC 回收。- 提交信息是给"未来的自己和其他人"看的,应体现"为什么改"
3.2 git reset ------ 移动指针的"时光机"
(1) 作用与机制
git reset 移动当前分支的 HEAD 指向,并根据模式同步更新索引和工作区。
设计动机:
- 灵活撤销:支持"软撤销(仅改指针)"到"硬撤销(彻底丢弃)"
- 本地历史整理:在推送前修正提交顺序、内容或拆分提交
(2) 三种模式对比
| 模式 | 移动 HEAD | 更新索引 | 更新工作区 | 典型用途 |
|---|---|---|---|---|
--soft |
✅ | ❌ | ❌ | 重新提交(合并提交) |
--mixed(默认) |
✅ | ✅ | ❌ | 取消提交,保留改动 |
--hard |
✅ | ✅ | ✅ | 彻底丢弃所有改动 |
(3) 风险警示
--hard不可逆,会直接丢弃工作区和暂存区数据- 仅用于未推送的本地提交,严禁用于公共历史
3.3 git revert ------ 安全的"反向提交"
(1) 作用与机制
git revert 生成一个新的提交,其内容是目标提交的反向差异(patch),从而"抵消"该提交的改动。
设计动机:
- 非破坏性:不修改已有历史,适合公共分支
- 审计友好:明确记录"何时、为何撤销某次变更"
(2) 与 reset 的本质区别
| 维度 | git reset |
git revert |
|---|---|---|
| 历史改写 | ✅ 是 | ❌ 否 |
| 适用分支 | 私有分支 | 公共分支 |
| 提交数量 | 减少 | 增加 |
| 协作安全 | ❌ 危险 | ✅ 安全 |
(3) 案例
#mermaid-svg-xhTwmxt0KQ7aYidi{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-xhTwmxt0KQ7aYidi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xhTwmxt0KQ7aYidi .error-icon{fill:#552222;}#mermaid-svg-xhTwmxt0KQ7aYidi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xhTwmxt0KQ7aYidi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xhTwmxt0KQ7aYidi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xhTwmxt0KQ7aYidi .marker.cross{stroke:#333333;}#mermaid-svg-xhTwmxt0KQ7aYidi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xhTwmxt0KQ7aYidi p{margin:0;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-id,#mermaid-svg-xhTwmxt0KQ7aYidi .commit-msg,#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label0{fill:#ffffff;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-xhTwmxt0KQ7aYidi .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label1{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-xhTwmxt0KQ7aYidi .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label2{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-xhTwmxt0KQ7aYidi .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label3{fill:#ffffff;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-xhTwmxt0KQ7aYidi .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label4{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-xhTwmxt0KQ7aYidi .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label5{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-xhTwmxt0KQ7aYidi .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label6{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-xhTwmxt0KQ7aYidi .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch-label7{fill:black;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-xhTwmxt0KQ7aYidi .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-xhTwmxt0KQ7aYidi .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-xhTwmxt0KQ7aYidi .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-xhTwmxt0KQ7aYidi .tag-hole{fill:#333;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-xhTwmxt0KQ7aYidi .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-xhTwmxt0KQ7aYidi .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-xhTwmxt0KQ7aYidi .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xhTwmxt0KQ7aYidi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main C0 C1 (bad commit) C2 (revert C1)
C2 的内容恰好抵消 C1,但 C1 仍然保留在历史中。
四、本地仓库内部:重组提交 DAG
Git 的提交历史是一个由 commit 节点与 parent 指针构成的有向无环图(DAG)。分支并非提交的容器,而只是指向图中某个节点的轻量可变指针。因此,创建或删除分支都不会改变 DAG 本身的拓扑结构,只会改变访问入口。
理解这一点,是区分 merge(保留节点)与 rebase(重写提交)的本质前提。
4.1 git merge ------ 保留历史的"汇合"
(1) git merge 的作用
merge 基于共同祖先与两分支最新提交执行三方合并,生成新的合并提交,完整保留分支演进轨迹。
设计动机:
- 非破坏性:不修改既有提交,历史可追溯
- 审计友好 :显式记录分支汇合点,适合公共分支(如
main、release)
(2) 案例演示
初始状态如下,main 与 feature 自 C0 分叉:
#mermaid-svg-t28OOJfW2fAAVLL9{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-t28OOJfW2fAAVLL9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-t28OOJfW2fAAVLL9 .error-icon{fill:#552222;}#mermaid-svg-t28OOJfW2fAAVLL9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-t28OOJfW2fAAVLL9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-t28OOJfW2fAAVLL9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-t28OOJfW2fAAVLL9 .marker.cross{stroke:#333333;}#mermaid-svg-t28OOJfW2fAAVLL9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-t28OOJfW2fAAVLL9 p{margin:0;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-id,#mermaid-svg-t28OOJfW2fAAVLL9 .commit-msg,#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label0{fill:#ffffff;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-t28OOJfW2fAAVLL9 .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label1{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-t28OOJfW2fAAVLL9 .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label2{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-t28OOJfW2fAAVLL9 .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label3{fill:#ffffff;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-t28OOJfW2fAAVLL9 .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label4{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-t28OOJfW2fAAVLL9 .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label5{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-t28OOJfW2fAAVLL9 .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label6{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-t28OOJfW2fAAVLL9 .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch-label7{fill:black;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-t28OOJfW2fAAVLL9 .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-t28OOJfW2fAAVLL9 .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-t28OOJfW2fAAVLL9 .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-t28OOJfW2fAAVLL9 .tag-hole{fill:#333;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-t28OOJfW2fAAVLL9 .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-t28OOJfW2fAAVLL9 .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-t28OOJfW2fAAVLL9 .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-t28OOJfW2fAAVLL9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C1 C2
在 main 执行 git merge feature,即使无冲突,也会生成独立合并提交 C3。main 前移指向 C3,feature 保持原位不动(分支仍存在),仍指向 C1。
#mermaid-svg-pW9gS812Xr8djKXt{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-pW9gS812Xr8djKXt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pW9gS812Xr8djKXt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pW9gS812Xr8djKXt .error-icon{fill:#552222;}#mermaid-svg-pW9gS812Xr8djKXt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pW9gS812Xr8djKXt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pW9gS812Xr8djKXt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pW9gS812Xr8djKXt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pW9gS812Xr8djKXt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pW9gS812Xr8djKXt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pW9gS812Xr8djKXt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pW9gS812Xr8djKXt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pW9gS812Xr8djKXt .marker.cross{stroke:#333333;}#mermaid-svg-pW9gS812Xr8djKXt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pW9gS812Xr8djKXt p{margin:0;}#mermaid-svg-pW9gS812Xr8djKXt .commit-id,#mermaid-svg-pW9gS812Xr8djKXt .commit-msg,#mermaid-svg-pW9gS812Xr8djKXt .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label0{fill:#ffffff;}#mermaid-svg-pW9gS812Xr8djKXt .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-pW9gS812Xr8djKXt .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label1{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-pW9gS812Xr8djKXt .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label2{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-pW9gS812Xr8djKXt .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label3{fill:#ffffff;}#mermaid-svg-pW9gS812Xr8djKXt .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-pW9gS812Xr8djKXt .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label4{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-pW9gS812Xr8djKXt .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label5{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-pW9gS812Xr8djKXt .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label6{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-pW9gS812Xr8djKXt .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch-label7{fill:black;}#mermaid-svg-pW9gS812Xr8djKXt .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-pW9gS812Xr8djKXt .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-pW9gS812Xr8djKXt .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-pW9gS812Xr8djKXt .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-pW9gS812Xr8djKXt .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-pW9gS812Xr8djKXt .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-pW9gS812Xr8djKXt .tag-hole{fill:#333;}#mermaid-svg-pW9gS812Xr8djKXt .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-pW9gS812Xr8djKXt .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-pW9gS812Xr8djKXt .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-pW9gS812Xr8djKXt .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-pW9gS812Xr8djKXt .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pW9gS812Xr8djKXt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C1 C2 C3 (merge commit)
可以看到,main 分支的提交历史拓扑呈非线性分支交汇。此时,即使feature 分支可以安全删除,C1 仍被 C3 的第二个父引用持有,历史完整性不受影响。这正是 merge 的核心价值:分支标签可以消失,但分叉事实被永久记录。
4.2 git rebase ------ 重写历史的"线性化"
(1) 作用与机制
rebase 将当前分支的提交序列"摘下",依次重放到目标分支最新提交之后,重新生成提交对象(Hash 变更)。
设计动机:
- 线性整洁:消除冗余合并提交,便于 Code Review
- 私有分支专用 :改写历史会影响协作,严禁用于公共分支
(2) 案例演示
沿用上述初始状态,在 feature 执行 git rebase main,将 C1 的变更重放到 C2 之后,生成新提交 C1'。
#mermaid-svg-syUjFhv2kNKn6uDc{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-syUjFhv2kNKn6uDc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-syUjFhv2kNKn6uDc .error-icon{fill:#552222;}#mermaid-svg-syUjFhv2kNKn6uDc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-syUjFhv2kNKn6uDc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-syUjFhv2kNKn6uDc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-syUjFhv2kNKn6uDc .marker.cross{stroke:#333333;}#mermaid-svg-syUjFhv2kNKn6uDc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-syUjFhv2kNKn6uDc p{margin:0;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-id,#mermaid-svg-syUjFhv2kNKn6uDc .commit-msg,#mermaid-svg-syUjFhv2kNKn6uDc .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label0{fill:#ffffff;}#mermaid-svg-syUjFhv2kNKn6uDc .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-syUjFhv2kNKn6uDc .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label1{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-syUjFhv2kNKn6uDc .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label2{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-syUjFhv2kNKn6uDc .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label3{fill:#ffffff;}#mermaid-svg-syUjFhv2kNKn6uDc .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-syUjFhv2kNKn6uDc .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label4{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-syUjFhv2kNKn6uDc .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label5{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-syUjFhv2kNKn6uDc .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label6{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-syUjFhv2kNKn6uDc .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch-label7{fill:black;}#mermaid-svg-syUjFhv2kNKn6uDc .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-syUjFhv2kNKn6uDc .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-syUjFhv2kNKn6uDc .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-syUjFhv2kNKn6uDc .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-syUjFhv2kNKn6uDc .tag-hole{fill:#333;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-syUjFhv2kNKn6uDc .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-syUjFhv2kNKn6uDc .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-syUjFhv2kNKn6uDc .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-syUjFhv2kNKn6uDc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C1 (abandoned) C2 C1' (rebased)
此时 feature 分支仍然存在,只是指向从 C1 变为 C1';原提交 C1 不再被任何分支引用 ,处于"失联"状态(仍可通过 reflog 找回,直到被 GC 回收)。这是 rebase 与 merge 的本质差异:merge 保留旧提交,rebase 遗弃旧提交。重放后的拓扑可简化为:
#mermaid-svg-G2xPmjjY4AEqLnMC{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-G2xPmjjY4AEqLnMC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G2xPmjjY4AEqLnMC .error-icon{fill:#552222;}#mermaid-svg-G2xPmjjY4AEqLnMC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G2xPmjjY4AEqLnMC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G2xPmjjY4AEqLnMC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G2xPmjjY4AEqLnMC .marker.cross{stroke:#333333;}#mermaid-svg-G2xPmjjY4AEqLnMC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G2xPmjjY4AEqLnMC p{margin:0;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-id,#mermaid-svg-G2xPmjjY4AEqLnMC .commit-msg,#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label0{fill:#ffffff;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-G2xPmjjY4AEqLnMC .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label1{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-G2xPmjjY4AEqLnMC .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label2{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-G2xPmjjY4AEqLnMC .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label3{fill:#ffffff;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-G2xPmjjY4AEqLnMC .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label4{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-G2xPmjjY4AEqLnMC .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label5{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-G2xPmjjY4AEqLnMC .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label6{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-G2xPmjjY4AEqLnMC .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch-label7{fill:black;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-G2xPmjjY4AEqLnMC .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-G2xPmjjY4AEqLnMC .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-G2xPmjjY4AEqLnMC .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-G2xPmjjY4AEqLnMC .tag-hole{fill:#333;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-G2xPmjjY4AEqLnMC .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-G2xPmjjY4AEqLnMC .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-G2xPmjjY4AEqLnMC .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G2xPmjjY4AEqLnMC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C2 C1'
随后切回 main 执行 git merge feature,由于 main 已是 feature 的祖先,由于 main 已是 feature 的祖先,Git 执行 Fast-forward,仅移动指针至 C1',不生成新的合并提交。
注意,Fast-forward 是操作标签。main分支最后的那个圆圈并非独立提交节点。
#mermaid-svg-uOfceSWJrgAlPJYX{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-uOfceSWJrgAlPJYX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uOfceSWJrgAlPJYX .error-icon{fill:#552222;}#mermaid-svg-uOfceSWJrgAlPJYX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uOfceSWJrgAlPJYX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uOfceSWJrgAlPJYX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uOfceSWJrgAlPJYX .marker.cross{stroke:#333333;}#mermaid-svg-uOfceSWJrgAlPJYX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uOfceSWJrgAlPJYX p{margin:0;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-id,#mermaid-svg-uOfceSWJrgAlPJYX .commit-msg,#mermaid-svg-uOfceSWJrgAlPJYX .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label0{fill:#ffffff;}#mermaid-svg-uOfceSWJrgAlPJYX .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-uOfceSWJrgAlPJYX .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label1{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-uOfceSWJrgAlPJYX .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label2{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-uOfceSWJrgAlPJYX .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label3{fill:#ffffff;}#mermaid-svg-uOfceSWJrgAlPJYX .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-uOfceSWJrgAlPJYX .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label4{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-uOfceSWJrgAlPJYX .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label5{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-uOfceSWJrgAlPJYX .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label6{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-uOfceSWJrgAlPJYX .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch-label7{fill:black;}#mermaid-svg-uOfceSWJrgAlPJYX .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-uOfceSWJrgAlPJYX .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-uOfceSWJrgAlPJYX .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-uOfceSWJrgAlPJYX .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-uOfceSWJrgAlPJYX .tag-hole{fill:#333;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-uOfceSWJrgAlPJYX .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-uOfceSWJrgAlPJYX .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-uOfceSWJrgAlPJYX .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uOfceSWJrgAlPJYX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C2 C1' Fast-forward
最终,main 分支的提交历史拓扑呈一条直线。此时,main 与 feature 均指向 C1'。
4.3 git cherry-pick ------ 精准摘取的"补丁移植"
(1)作用与机制
git cherry-pick 将指定提交所引入的**差异(patch)**提取出来,并应用到当前分支,生成一个新的提交。若目标分支已包含相同或语义等价的改动,cherry-pick 可能触发冲突,需手动解决。
设计动机:
- 跨分支移植:仅复制某次提交的改动,而不合并整个分支
- 多版本维护 :同一修复需同时应用于多个发布分支(如
release-1.0、release-2.0)
(2)案例演示
在 main 分支上执行 git cherry-pick C1 后,提交历史如下:
#mermaid-svg-ofRZjROnPEPSHdZI{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-ofRZjROnPEPSHdZI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ofRZjROnPEPSHdZI .error-icon{fill:#552222;}#mermaid-svg-ofRZjROnPEPSHdZI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ofRZjROnPEPSHdZI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ofRZjROnPEPSHdZI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ofRZjROnPEPSHdZI .marker.cross{stroke:#333333;}#mermaid-svg-ofRZjROnPEPSHdZI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ofRZjROnPEPSHdZI p{margin:0;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-id,#mermaid-svg-ofRZjROnPEPSHdZI .commit-msg,#mermaid-svg-ofRZjROnPEPSHdZI .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms',verdana,arial,sans-serif;font-family:var(--mermaid-font-family);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label0{fill:#ffffff;}#mermaid-svg-ofRZjROnPEPSHdZI .commit0{stroke:hsl(240, 100%, 46.2745098039%);fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight0{stroke:hsl(60, 100%, 3.7254901961%);fill:hsl(60, 100%, 3.7254901961%);}#mermaid-svg-ofRZjROnPEPSHdZI .label0{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow0{stroke:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label1{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit1{stroke:hsl(60, 100%, 43.5294117647%);fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight1{stroke:rgb(0, 0, 160.5);fill:rgb(0, 0, 160.5);}#mermaid-svg-ofRZjROnPEPSHdZI .label1{fill:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow1{stroke:hsl(60, 100%, 43.5294117647%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label2{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit2{stroke:hsl(80, 100%, 46.2745098039%);fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight2{stroke:rgb(48.8333333334, 0, 146.5000000001);fill:rgb(48.8333333334, 0, 146.5000000001);}#mermaid-svg-ofRZjROnPEPSHdZI .label2{fill:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow2{stroke:hsl(80, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label3{fill:#ffffff;}#mermaid-svg-ofRZjROnPEPSHdZI .commit3{stroke:hsl(210, 100%, 46.2745098039%);fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight3{stroke:rgb(146.5000000001, 73.2500000001, 0);fill:rgb(146.5000000001, 73.2500000001, 0);}#mermaid-svg-ofRZjROnPEPSHdZI .label3{fill:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow3{stroke:hsl(210, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label4{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit4{stroke:hsl(180, 100%, 46.2745098039%);fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight4{stroke:rgb(146.5000000001, 0, 0);fill:rgb(146.5000000001, 0, 0);}#mermaid-svg-ofRZjROnPEPSHdZI .label4{fill:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow4{stroke:hsl(180, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label5{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit5{stroke:hsl(150, 100%, 46.2745098039%);fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight5{stroke:rgb(146.5000000001, 0, 73.2500000001);fill:rgb(146.5000000001, 0, 73.2500000001);}#mermaid-svg-ofRZjROnPEPSHdZI .label5{fill:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow5{stroke:hsl(150, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label6{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit6{stroke:hsl(300, 100%, 46.2745098039%);fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight6{stroke:rgb(0, 146.5000000001, 0);fill:rgb(0, 146.5000000001, 0);}#mermaid-svg-ofRZjROnPEPSHdZI .label6{fill:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow6{stroke:hsl(300, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch-label7{fill:black;}#mermaid-svg-ofRZjROnPEPSHdZI .commit7{stroke:hsl(0, 100%, 46.2745098039%);fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight7{stroke:rgb(0, 146.5000000001, 146.5000000001);fill:rgb(0, 146.5000000001, 146.5000000001);}#mermaid-svg-ofRZjROnPEPSHdZI .label7{fill:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .arrow7{stroke:hsl(0, 100%, 46.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .branch{stroke-width:1;stroke:#333333;stroke-dasharray:2;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-label{font-size:10px;fill:#000021;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-label-bkg{font-size:10px;fill:#ffffde;opacity:0.5;}#mermaid-svg-ofRZjROnPEPSHdZI .tag-label{font-size:10px;fill:#131300;}#mermaid-svg-ofRZjROnPEPSHdZI .tag-label-bkg{fill:#ECECFF;stroke:hsl(240, 60%, 86.2745098039%);}#mermaid-svg-ofRZjROnPEPSHdZI .tag-hole{fill:#333;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-merge{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-reverse{stroke:#ECECFF;fill:#ECECFF;stroke-width:3;}#mermaid-svg-ofRZjROnPEPSHdZI .commit-highlight-inner{stroke:#ECECFF;fill:#ECECFF;}#mermaid-svg-ofRZjROnPEPSHdZI .arrow{stroke-width:8;stroke-linecap:round;fill:none;}#mermaid-svg-ofRZjROnPEPSHdZI .gitTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ofRZjROnPEPSHdZI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} main feature C0 C1 (bugfix) C2 C1' (cherry-picked)
此时:
C1仍保留在feature分支上,未被修改或移除main分支新增提交C1',其代码改动与C1完全一致 ,但拥有全新的 Commit Hash- 提交历史呈线性增长,不引入分支交汇节点
这正是
cherry-pick的本质:复制一次提交的"补丁",而非移动或合并整个分支。
4.4 对比总结
| 维度 | git merge |
git rebase |
git cherry-pick |
|---|---|---|---|
| 历史形态 | 非线性(保留分支) | 线性(改写历史) | 线性(复制提交) |
| 原分支变化 | 不变 | 不变(提交被"挪走") | 不变 |
| 提交 Hash | 不变 | 改变 | 改变 |
| 适用场景 | 公共分支合并 | 本地/私有分支整理 | 跨分支补丁移植 |
| 安全性 | 高(非破坏性) | 低(改写历史) | 中(生成新提交) |
五、本地 ⇄ 远程仓库:分布式同步
fetch / pull / push 解决的是本地仓库 ⇄ 远程仓库 的同步问题,核心设计原则是传输与合并解耦。
5.1 git fetch ------ 只下载不合并
(1) 作用与机制
git fetch 从远程仓库下载对象和更新引用(如 refs/remotes/origin/*),绝不修改本地分支。
设计动机:
- 只读同步:先观察远程变化,再决定是否合并
- 安全预览 :避免
pull的"盲合并"风险
(2) 数据流向
text
远程仓库
│
│ git fetch
▼
本地仓库(远程跟踪分支,如 origin/main)
│
│ merge / rebase
▼
本地分支(如 main)
5.2 git pull ------ 传输 + 合并的快捷方式
(1) 作用与机制
git pull = git fetch + git merge(默认)或 git rebase(配置后)。
设计动机:
- 操作简化:减少高频同步的打字成本
- 可配置策略 :通过
pull.rebase控制合并行为
(2) 风险与最佳实践
-
默认
merge会产生大量"无意义的合并提交" -
推荐配置:
bashgit config --global pull.rebase true -
在不确定时,显式使用
fetch + rebase更安全
5.3 git push ------ 上传并更新引用
(1) 作用与机制
git push 将本地提交上传至远程仓库,并更新远程引用。若远程历史包含本地没有的提交,推送会被拒绝。
设计动机:
- 防覆盖保护:避免无意覆盖他人工作
- 强制推送需显式声明 :
--force-with-lease比--force更安全
(2) 关键细节
push只更新匹配的引用(默认当前分支)--force-with-lease会检查远程引用是否已被他人更新- 推送标签需显式指定:
git push --tags
六、只读观测
status / diff / log / reflog 属于 Git 的只读观测层。它们不修改任何域中的数据,也不移动引用,仅用于读取当前状态、对比差异或遍历历史,是辅助所有写操作的"仪表盘"。
6.1 git status ------ 三域状态快照
git status 的本质是同时对比三个数据域:
HEAD:当前分支指向的提交(本地仓库)- 索引(Index):暂存区(下一跳提交的内容)
- 工作区(Working Directory):当前磁盘上的文件状态
基于此,它输出三类信息:
| 类型 | 含义 |
|---|---|
| 已暂存的变更 | 索引与 HEAD 不同,将进入下次提交 |
| 未暂存的变更 | 工作区与索引不同,尚未 add |
| 未跟踪的文件 | 不在索引中,也不属于任何提交 |
设计动机 :在执行
commit、reset或checkout前,先执行git status确认三域是否处于预期状态,可以避免绝大多数误操作。
6.2 git diff ------ 差异引擎
git diff 是 Git 中最通用的对比工具,其核心语义是"比较两个对象树之间的差异"。根据对比对象的不同,常见用法如下:
| 命令 | 比较对象 | 典型用途 |
|---|---|---|
git diff |
工作区 vs 暂存区 | 查看尚未暂存的改动 |
git diff --staged |
暂存区 vs HEAD |
查看即将提交的改动 |
git diff HEAD |
工作区 vs HEAD |
查看所有未提交的改动 |
git diff A B |
两次提交之间 | 审查历史变更或分支差异 |
6.3 git log ------ 历史遍历
git log 沿 parent 指针遍历提交 DAG,是理解提交拓扑的主要入口。
- 默认按时间倒序输出当前分支可达的提交
- 通过参数可以控制遍历路径与展示形式:
--oneline:单行摘要,适合快速浏览--graph:ASCII 拓扑图,直观展示分支与合并--all --decorate:显示所有分支与标签,避免遗漏并行历史
6.4 git reflog ------ 引用的"黑匣子"
git reflog 记录的是引用的移动历史,而非提交本身的变化。
- 记录对象:
HEAD及所有分支引用的每一次移动 - 覆盖范围:包括
commit、reset、checkout、merge、rebase等一切改变引用的操作 - 关键特性:
- 本地私有 :不会被
push到远程仓库 - 生存周期独立 :即使提交不再被任何分支引用(如
rebase后的旧提交),只要还在reflog中,就可通过 Hash 找回 - 最终回收:过期条目会被 Git 的 GC 机制清理
- 本地私有 :不会被
设计动机 :
reflog是 Git 的"后悔药"。它是唯一能解释"我的提交去哪了"的工具,也是理解"为什么reset --hard并非绝对不可逆"的关键。