news 2026/9/7 17:31:55

Mermaid GitGraph 图完全指南:从 commit/branch/merge 语法到主题变量的源码级解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mermaid GitGraph 图完全指南:从 commit/branch/merge 语法到主题变量的源码级解析

Mermaid GitGraph 图完全指南:从 commit/branch/merge 语法到主题变量的源码级解析

【免费下载链接】mermaidGeneration of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown项目地址: https://gitcode.com/GitHub_Trending/me/mermaid

本文基于 Mermaid 仓库的官方语法文档 gitgraph.md 展开,系统讲解 Git Graph 图的声明式语法——commitbranchcheckoutmergecherry-pick五大操作,全部gitGraph配置项(showBranchesmainBranchNameparallelCommits等)、LR/TB/BT方向控制与git0~git7系列主题变量。结合 packages/mermaid/src/diagrams/git/gitGraphAst.ts 等源码,你将既会写图,也能理解每个语法糖背后的状态机与校验规则。

什么是 Git Graph 图

Git Graph 是对 Git 提交与 Git 操作(命令)在各分支上的图形化表示。这类图对开发者和 DevOps 团队分享 Git 分支策略特别有用,例如直观展示 Git Flow 的工作方式。

一个最基础的示例,标题通过 front matter 的title指令设置:

Mermaid 支持四个基本 Git 操作:

  • commit:在当前分支上表示一次新提交;
  • branch:创建并切换到新分支,将其设为当前分支(等价于 git 中创建分支并 checkout);
  • checkout:切换到已存在的分支,并将其设为当前分支(checkoutswitch可以互换使用);
  • merge:把一个已存在的分支合并进当前分支。

借助这几个关键命令,你可以非常快速地在 Mermaid 中画出 Git 图。

从源码结构看,GitGraph 图由 gitGraphDiagram.ts 注册为标准的DiagramDefinition:解析器(gitGraphParser.ts,由 Jison 生成)、数据模型(gitGraphAst.ts导出的db对象)、渲染器(gitGraphRenderer.ts)与样式(styles.js)各司其职。所有状态都收敛在 gitGraphAst.ts 的一个ImperativeState中,包含commits(提交映射)、branches(分支到 HEAD 提交的映射)、currBranch(当前分支)、direction(方向,默认'LR')与自增序号seq等字段,这正是"每条命令按书写顺序依次作用"这一声明式语义的实现基础。

声明式语法与初始状态

GitGraph 语法非常直接:它是一种声明式写法,每个提交按其在代码中出现的顺序依次画在时间线上,即按插入顺序逐条执行命令。

第一步是用gitGraph关键字声明图类型,它告诉 Mermaid 你要画一张 Git 图并按此解析后续代码。

每个 Git 图都从main分支初始化,因此除非创建其他分支,提交默认都会落在main上——这与 Git 本身的工作方式一致(最初总是从 main 分支,即旧称的 master 分支开始),并且main分支默认就是当前分支

三个提交都落在默认main分支上的最小图:

仔细观察上面的图:默认分支main上有三个提交,并且每个提交都被赋予了唯一且随机的 ID。源码印证了这一点:当未提供id时,commit 函数 生成的 ID 是seq + '-' + 7位随机串(随机串由 getID() 产生)。

自定义 commit ID

声明提交时可以用id属性指定自定义 ID,格式为id:加双引号包裹的值,例如commit id: "your_custom_id"

在实现中,commit会把idmsg统一经过common.sanitizeText清洗;若 ID 已存在,源码只记录 warn("Commit ID ... already exists"),不会中断渲染。

修改 commit 类型

Mermaid 中提交有三种类型,在图中的图形略有差异:

  • NORMAL:默认提交类型,实心圆表示;
  • REVERSE:强调某次提交为"回退提交",带叉的实心圆表示;
  • HIGHLIGHT:高亮某次提交,实心矩形表示。

type属性声明,例如commit type: HIGHLIGHT。未指定时默认取NORMAL。三种类型与自定义 ID 组合的示例:

添加 Tag

你可以像 Git 中的 tag/release 概念一样,用tag属性给提交打标签:commit tag: "your_custom_tag"idtypetag这些属性可以在同一条提交声明中任意混搭:

创建新分支

使用branch关键字并给出新分支名。分支名必须唯一,不能与已有分支重名;如果分支名容易与关键字混淆,需要用""引号包裹。用法示例:branch developbranch "cherry-pick"

Mermaid 读到branch时会创建该分支并将其设为当前分支,等价于 Git 中"创建并切换"。这一点在源码 branch 函数 中可以直接看到:它先校验重名(抛出 "Trying to create an existing branch..." 错误),然后把新分支的 HEAD 指向当前head,最后自动调用checkout(name)

起始于默认main分支并推送两个提交;创建develop分支后,其成为当前分支,之后的所有提交都落在develop上。

切换(checkout)已存在分支

使用checkout关键字并给出一个已存在的分支名;若找不到该分支会报控制台错误。用法示例:checkout develop

源码 checkout 函数 的校验逻辑:分支不存在时抛出 "Trying to checkout branch which is not yet created" 错误;存在时更新currBranch,并把head定位到该分支记录的 HEAD 提交(若该分支尚无提交则head置为 null)。

在上一例基础上,用checkout main把当前分支切回main,其后的两个提交注册到main上。

合并两个分支

使用merge关键字并给出要合并进来的分支名。找不到该分支会报错;只能合并两个不同的分支,不能把一个分支合并到自身(会抛错)。用法示例:merge develop

Mermaid 读到merge时,找到目标分支及其 HEAD 提交,把它与当前分支的 HEAD 提交连接,每次合并都会产生一个合并提交(merge commit),图中以实心双圆表示。

merge 函数 的校验链相当严格,与文档描述的规则一一对应:

  1. 当前分支与目标分支是同一分支 → "Cannot merge a branch to itself";
  2. 当前分支没有任何提交 → "Current branch (...) has no commits";
  3. 目标分支不存在 → "Branch to be merged (...) does not exist";
  4. 目标分支没有任何提交 → "Branch to be merged (...) has no commits";
  5. 两个分支 HEAD 相同 → "Both branches have same head";
  6. 自定义id与已有提交 ID 冲突 → 报错并要求换一个唯一 ID。

develop被合并进main,产生一个合并提交;当前分支仍是main,最后两个提交注册到main

合并提交也可以像提交一样装饰属性,可以一个都不用、部分用或全用:

  • id:用自定义 ID 覆盖默认 ID;
  • tag:给合并提交添加自定义 tag;
  • type:覆盖合并提交的默认形状(使用前面提到的 commit 类型)。

例如:merge develop id: "my_custom_id" tag: "my_custom_tag" type: REVERSE。下面是一个多分支交叉的完整例子,最后一行演示了带属性的合并:

从其他分支 cherry-pick 提交

与真实 Git 类似,Mermaid 支持用cherry-pick关键字把另一个分支上的提交摘到当前分支。必须用id属性给出要摘取的提交 ID:cherry-pick id: "your_custom_id"。执行后,当前分支上会创建一个代表 cherry-pick 的新提交,以樱桃图形高亮,并带有一个标注来源提交 ID 的 tag。

五条重要规则(与 cherryPick 函数 的校验逻辑一致):

  1. 必须提供已存在的提交id,不存在则报错——因此要先用commit id:"..."的方式声明提交;
  2. 被摘取的提交不能已存在于当前分支,cherry-pick 的提交必须来自其他分支;
  3. 当前分支在执行 cherry-pick 之前必须至少有一个提交,否则抛错;
  4. cherry-pick 合并提交时,parent属性必填,省略或提供无效父提交 ID 都会抛错;
  5. 指定的父提交必须是该合并提交的直接父提交(源码用sourceCommit.parents.includes(parentCommitId)校验)。

示例:

源码层面还有一个细节:cherry-pick 生成的提交类型是commitType.CHERRY_PICK,若未显式提供 tag,会自动附加cherry-pick:<来源ID>(合并提交还会带|parent:<父ID>)作为 tag,这就是图中樱桃节点上出现来源标注的由来。

GitGraph 专属配置项

Mermaid 提供一组gitGraph配置项,可以在 front matter 的config指令中设置。完整清单:

配置项类型默认值说明
showBranchesBooleantrue设为false时图中不显示分支名与分支线
showCommitLabelBooleantrue设为false时图中不显示提交标签
mainBranchNameStringmain默认/根分支的名称
mainBranchOrderNumber0main 分支在分支列表中的位置,默认 0 即排在最前
parallelCommitsBooleanfalse设为true时,距父提交 x 个距离的提交画在同一层,不体现时间先后
rotateCommitLabelBooleantrue提交标签是否旋转 45 度(详见下文布局小节)

这组配置的类型定义见 config.type.ts 中的GitGraphDiagramConfig,默认值由 schemas/config.schema.yaml 加载(defaultConfig.ts 中从 JSON Schema 读取),而运行时读取走 getConfig():用cleanAndMerge把默认值与用户通过mermaid.initialize()或 front matter 传入的gitGraph配置合并。单元测试 gitGraph.spec.ts 也逐条断言了showBranchesshowCommitLabelrotateCommitLabelparallelCommits属性存在。

隐藏分支名和分支线

showBranches: false隐藏分支名和线(渲染器 gitGraphRenderer.ts 在showBranches为真时才绘制分支元素):

提交标签布局:旋转或水平

Mermaid 支持两种提交标签布局,默认是旋转(rotated):标签放在提交圆下方并旋转 45 度,便于阅读,对长标签特别友好;另一种是水平(horizontal):标签水平居中放在提交圆下方,不旋转,适合短标签。用rotateCommitLabel关键字切换,默认true(旋转)。

旋转布局:

水平布局(仅把rotateCommitLabel改为false,图体不变):

隐藏提交标签

showCommitLabel: false隐藏提交标签。与上一节组合使用的示例(showBranchesshowCommitLabel同时关闭):

自定义 main 分支名

mainBranchName把默认分支改成任意字符串。下面把默认分支改名为MetroLine1,画了一张"想象中的地铁线路图":

注意这里checkout MetroLine1merge MetroLine3merge MetroLine2 tag:"MY JUNCTION"中的名字都必须与新分支名一致——从源码 状态初始化 可见,mainBranchName会同时决定初始currBranchbranchConfig的初始键。

自定义分支顺序

默认情况下,分支按它们在图中定义/出现的顺序展示。用order关键字(正整数)可以自定义顺序,写在分支定义后面:

Mermaid 遵循order的优先顺序规则:

  1. main 分支默认 order 为0,永远最先展示(除非用mainBranchOrder配置改动它);
  2. 未指定order的分支,按出现顺序展示;
  3. 指定了order的分支,按order值排序展示。

要完全控制所有分支的顺序,必须为所有分支都定义order

再看一个配合mainBranchOrder: 2的例子:

排序结果:test2test3(未指定 order,按定义顺序)→test4(order 1)→main(order 2,因覆盖了mainBranchOrder而不再置顶)→test1(order 3)。

排序逻辑的实现在 getBranchesAsObjArray():未显式指定 order 的分支被赋予0.<索引>形式的浮点数(即"按出现顺序"排在前),再与显式 order 一起统一按数值升序排列——这解释了为什么"无 order 分支"整体排在"有 order 分支"之前。

方向控制:LR / TB / BT(v10.3.0+)

Mermaid 支持三种图方向:Left-to-Right(默认)、Top-to-BottomBottom-to-Top。写法是在gitGraph关键字后加LR:TB:BT:

左到右(默认,LR:

默认方向是提交从左到右展开、分支上下堆叠。也可以显式写出LR:

上到下(TB:

TB方向下提交从上到下展开,分支左右并排。在gitGraph后加TB:

下到上(BT:)(v11.0.0+)

BT方向下提交从下到上展开,分支左右并排。在gitGraph后加BT:

方向由解析器回调setDirection写入状态(初始值'LR'),渲染器根据direction决定坐标映射。

并行提交(v10.8.0+)

默认情况下 GitGraph 通过提交的水平位置传达时间信息:例如两个提交距父提交同样远时,先写的会画得更靠近父提交。开启parallelCommits: true可关闭这种时间差——距父提交 x 个距离的提交会画在同一层。

时间顺序模式(默认,parallelCommits: false):

并行模式(parallelCommits: true):

主题与主题变量

Mermaid 支持预定义主题,也可以用主题变量覆盖任何主题的既有取值。GitGraph 可用的预定义主题:baseforestdarkdefaultneutral。切换主题可以用initialize调用或 front matter 指令(directives 说明),主题机制详见 theming 文档。

以同一张多分支图分别套用不同主题为例(theme: 'base'/'forest'/'default'/'dark'/'neutral'只需替换 front matter 中的theme值):

用主题变量定制外观

主题变量控制图各元素的颜色与排版。以default主题为基准示例,覆盖方式统一是 front matter 的themeVariables

重要说明:主题变量最多覆盖8 个分支的颜色/样式,超出后循环复用——第 9 个分支使用第 1 个分支(索引 0)的取值。

分支颜色git0~git7git0驱动第 1 个分支,git1驱动第 2 个,依此类推:

分支标签颜色gitBranchLabel0~gitBranchLabel7,规则相同:

由于只有 8 组标签变量,branch8branch9会分别复用索引 0(main)与索引 1(branch1)的配色——即分支主题变量循环复用

提交标签颜色与字号commitLabelColorcommitLabelBackgroundcommitLabelFontSize

Tag 标签tagLabelColortagLabelBackgroundtagLabelBorder控制 tag 的文字颜色、背景与边框;tagLabelFontSize控制 tag 字号:

高亮提交颜色gitInv0~gitInv7按分支索引控制各分支上HIGHLIGHT提交的颜色(同样最多 8 个、循环复用):

仓库中的实现与测试索引

想在源码层面继续深入 GitGraph,可以从以下入口按调用链阅读(均在仓库相对路径下):

  • gitGraphDiagram.ts:图定义注册(parser + db + renderer + styles);
  • gitGraphAst.ts:命令执行与状态机核心,commit/branch/merge/cherryPick/checkout的校验与合并配置逻辑;
  • gitGraphParser.ts:由 Jison 生成的语法解析器,负责把文本切分为命令并回调上述函数;
  • gitGraphRenderer.ts:SVG 绘制,消费showCommitLabelrotateCommitLabelparallelCommitsshowBranches等配置;
  • gitGraphTypes.ts:CommitcommitType(NORMAL/REVERSE/HIGHLIGHT/MERGE/CHERRY_PICK)等类型定义;
  • config.type.ts:GitGraphDiagramConfig配置类型;
  • gitGraph.spec.ts:单元测试,覆盖各命令行为与配置读取;
  • e2e/diagrams/gitgraph/:100 余个端到端渲染用例(.mmd文件),覆盖 cherry-pick、merge 属性、order排序等场景,是观察各语法实际渲染效果的最好素材;
  • 本文依据的文档源文件位于 packages/mermaid/src/docs/syntax/gitgraph.md(docs/syntax/gitgraph.md 为其自动生成的站点版本)。

小结

GitGraph 图用不到十行声明式文本,就能表达 commit、branch、checkout、merge 与 cherry-pick 构成的完整分支协作流程;每个提交支持id/type/tag属性,每条branch支持ordergitGraph关键字支持LR:/TB:/BT:方向,front matter 的gitGraph配置节与git0~git7gitBranchLabel*commitLabel*tagLabel*gitInv*主题变量则覆盖布局、命名、排序与外观的全部定制需求。配合源码中的严格校验(重名分支、空分支合并、cherry-pick 父提交约束等),你在写图时遇到的每个报错都能在 gitGraphAst.ts 中找到对应逻辑。

【免费下载链接】mermaidGeneration of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown项目地址: https://gitcode.com/GitHub_Trending/me/mermaid

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 17:28:44

STM32模拟I2C从机实战:状态机设计、中断处理与踩坑总结

简介&#xff1a;面向STM32/GD32嵌入式开发者&#xff0c;提供一套C语言编写的模拟I2C从机demo代码&#xff0c;解决MCU缺少硬件I2C从机控制器、或应用场景不适合占用中断资源时的从机通信问题。代码在GD32F130平台验证&#xff0c;思路可迁移到其他STM32系列&#xff0c;主机读…

作者头像 李华
网站建设 2026/9/7 17:28:39

随机森林在市场结构预测中的量化实践:从三分类建模到仓位管理

先说个我自己踩坑踩出来的结论&#xff1a;在量化交易里用机器学习最稳的姿势&#xff0c;不是让模型猜下一步涨几个点&#xff0c;而是先让它回答市场当前处于什么结构。随机森林是我在这条路上试了一圈后一直留用的模型&#xff0c;这篇文章就用随机森林做一次市场结构预测的…

作者头像 李华
网站建设 2026/9/7 17:28:32

二阶锥规划与主动配电网动态重构:MATLAB+YALMIP+CPLEX实战

这些年做配电网优化方向的仿真&#xff0c;我接触最多的场景之一&#xff0c;就是基于二阶锥规划的主动配电网动态重构。这个方向在学术论文里出镜率很高&#xff0c;但真正落到代码层面、能用MATLABYALMIPCPLEX完整跑通的人并不多。题主这个标题&#xff0c;其实把一条很清晰的…

作者头像 李华
网站建设 2026/9/7 17:28:07

AI生成代码+嵌入式验证:从草稿到可靠工程的必经之路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 17:25:04

Git从入门到实战:安装配置、核心命令与报错排查全攻略

说个真实场景&#xff1a;上个月有个同事在群里发了一张报错截图&#xff0c;内容是“git : 无法将‘git’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”&#xff0c;下面跟了一串“怎么办在线等”。我问他装没装Git&#xff0c;他理直气壮说装了&#xff0c;结果一看系…

作者头像 李华