Git 命令全景解析:基于数据流向的认知框架

文章目录

    • [一、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 既像撤销又像历史改写?为什么 fetchpull 必须分开理解?为什么某些操作是"危险"的,而另一些是"安全"的?要回答这些问题,需要的不只是一份更长的命令列表,而是一套能够解释 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 命令分为两层,这是理解"为什么有些命令行为反直觉"的关键:

设计动机

Git 早期就明确区分"用户界面"与"存储引擎"。上层命令是对底层操作的封装,因此:

  • 同一目标可以有多种上层命令实现(merge / rebase
  • 某些上层命令会组合其他上层命令来完成复杂流程(如 pull 默认等价于 fetch + merge
  • 上层命令最终依赖底层命令操作 Git 的对象库与引用(如 commit 内部会调用 write-treecommit-treeupdate-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 本身是一个游离提交,不属于任何分支 DAG
  • stash 不会自动删除,需显式 droppop
  • git 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 基于共同祖先与两分支最新提交执行三方合并,生成新的合并提交,完整保留分支演进轨迹。

设计动机

  • 非破坏性:不修改既有提交,历史可追溯
  • 审计友好 :显式记录分支汇合点,适合公共分支(如 mainrelease

(2) 案例演示

初始状态如下,mainfeatureC0 分叉:
#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 回收)。这是 rebasemerge 的本质差异: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.0release-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 会产生大量"无意义的合并提交"

  • 推荐配置:

    bash 复制代码
    git 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
未跟踪的文件 不在索引中,也不属于任何提交

设计动机 :在执行 commitresetcheckout 前,先执行 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 及所有分支引用的每一次移动
  • 覆盖范围:包括 commitresetcheckoutmergerebase 等一切改变引用的操作
  • 关键特性:
    • 本地私有 :不会被 push 到远程仓库
    • 生存周期独立 :即使提交不再被任何分支引用(如 rebase 后的旧提交),只要还在 reflog 中,就可通过 Hash 找回
    • 最终回收:过期条目会被 Git 的 GC 机制清理

设计动机reflog 是 Git 的"后悔药"。它是唯一能解释"我的提交去哪了"的工具,也是理解"为什么 reset --hard 并非绝对不可逆"的关键。

参考资料

Git Cheat Sheet

Git - Reference

Git - git Documentation

相关推荐
星e雨2 小时前
Window Git安装
git
旧梦星轨2 小时前
Git Flow 工作流实践
git·gitee·gitlab·github
༄久梦༒长醉༻4 小时前
技术笔记——Git Worktree工作树
笔记·git
彧azz5 小时前
Git 学习指南:从入门到进阶的完整实践手册
git·学习
浅念-15 小时前
一文吃透Git:本地操作|冲突处理|远程协作|GitFlow工作流详解
大数据·git·elasticsearch·搜索引擎·gitflow
滕州市燕猫虎计算机科技工作室个体工商户19 小时前
Git常用命令汇总
git
czhc114007566321 小时前
2026-09-11 一日综合:树的父链、git 概念、三方死锁、静默失败
大数据·git·elasticsearch
ChampaignWolf21 小时前
abapgit-agent:用 Git 当中介,让 Claude Code 自己完成 ABAP 闭环开发
git·ai·abap·claude·abapgit·mcp
嘴贱欠吻!21 小时前
如何成为 CJMP 贡献者:AtomGit贡献流程与要求
git·ci/cd