Cutter 发布流程完全指南:从功能冻结到正式 Release 的全链路操作手册
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
导读
本文以 Cutter(基于 rizin 的自由开源逆向工程平台)官方发布流程文档为骨架,系统梳理从功能冻结、版本锁定、版本号更新、RC 预发布、全平台回归测试到正式 Release 发布与公告的完整操作链。无论你是 Cutter 的维护者、打包者,还是希望理解开源桌面应用发布工程实践的开发者,读完本文都能掌握:如何管理 translations 子模块与 Crowdin 同步、如何将 dev 合并到 stable 实现功能冻结、如何在多个文件中同步更新版本号、如何正确创建 RC 标签与 GitHub Release,以及如何在发布前执行一份快速但有效的冒烟测试清单。
1. 发布流程总览
Cutter 的发布流程(见 release-procedure.rst)是一条从「翻译同步」到「正式公告」的流水线,核心目标是在保证 stable 分支质量的同时,让 dev 分支的开发不被发布工作阻断。整体可以划分为五个阶段:
- 发布前准备:同步翻译、合并 dev 到 stable(功能冻结)、锁定第三方组件版本、更新版本号。
- 候选版本(RC):打 RC 标签、创建 pre-release、等待各平台打包产物。
- 回归测试:在所有操作系统上执行基础测试流程(
Basic testing procedure)。 - 正式发布:更新版本号、打正式标签、填写 Release Notes、发布公告、关闭里程碑。
- Bugfix 发布:从 dev 中 cherry-pick 修复到 stable,并递增第三位版本号。
流程文档中强调:功能冻结(feature-freeze)可以提前发生,即在 dev 分支继续开发的同时把当前状态并入 stable,这样发布准备工作与日常开发可以并行推进,互不阻塞。
2. 发布前准备:翻译、分支合并与版本锁定
2.1 更新 translations 子模块
Cutter 的界面翻译通过 Crowdin 平台协作完成,翻译文件以 git submodule 的形式嵌入仓库。发布前的第一步是确保翻译处于最新状态:
- 确认最新翻译归档已在仓库中:Crowdin 的自动化 Pull Request 通常会自动合入翻译更新(例如
cutter-translations仓库中的自动 PR)。若尚未合入,需要先手动合并。 - 更新 Cutter 仓库中的子模块指针:将
translations子模块指向最新的翻译提交。
仓库中 deploy_translations.sh 展示了翻译子模块的双向工作流:脚本执行git submodule update translations,随后将 Cutter 生成的翻译文件(如cutter_fr.ts)整理为 Crowdin 可识别的单一文件并推送回cutter-translations仓库。也就是说,发布前从 Crowdin 拉取翻译、发布后向 Crowdin 推送新字符串,构成了翻译的完整闭环。
2.2 合并 dev 到 stable(功能冻结)
将 dev 分支的当前状态合并进 stable,这一步骤允许提前执行:
- 提前合并:可以在功能冻结时就把 dev 合并到 stable,之后 dev 继续接受新功能开发,而 stable 只接受 bugfix 与发布相关改动。
- 子模块指针约束:stable 分支上的rizin 子模块应指向 rizin 仓库的 stable 分支提交,dev 分支上的 rizin 子模块应指向 rizin 的 dev 分支提交。这保证了发布分支始终基于稳定的 rizin 版本,而不是未发布的开发版本。
2.3 锁定 rzghidra 与 rzdec 版本
打包脚本(packaging scripts)会从外部仓库拉取反编译器插件源码。发布前必须锁定这些依赖的具体版本,指定 tag 或 commit hash,避免发布包中混入非预期的上游变更:
- rzghidra:即 Ghidra 反编译器的 rizin 原生集成插件。在 dist/CMakeLists.txt 中,它通过
ExternalProject_Add拉取,其中GIT_TAG字段控制版本(源码中注释给出了v0.3.0标签与某个 commit hash 的示例,当前默认指向dev分支);发布打包时需将其改为具体的 tag 或 commit。 - rzdec:RetDec 反编译器的 rizin 插件,同样需要在打包配置中锁定版本。
注意:源码注释中提醒「disable this line when using commit hash」——当使用 commit hash 锁定时应关闭
GIT_SHALLOW ON,以免浅克隆无法获取指定提交。从源码结构看(dist/CMakeLists.txt),这正是发布流程第 3 步对应的实现位置。
3. 更新版本号:全仓库同步
版本号不是只改一个文件,而需要在整个代码库中保持一致。发布流程文档列出的更新清单如下(部分文件在当前仓库中的实际路径已发生变化,以仓库实际内容为准):
| 原文档列举项 | 当前仓库中的实际位置 | 说明 |
|---|---|---|
appveyor.yml | 当前仓库根目录未见该文件 | 早期 Windows CI 配置;以当前 CI 实际文件为准 |
docs/sourc/conf.py | docs/conf.py | Sphinx 文档配置,含version/release字段 |
docs/source/index.rst | docs/source/index.rst | 文档首页中的版本号展示 |
CMakeLists.txt | CMakeLists.txt | 核心版本定义处(见下文) |
Cutter.appdata.xml | src/re.rizin.cutter.appdata.xml | AppData 元数据中的<releases>版本信息 |
保险起见,建议全代码库搜索旧版本号,避免遗漏任何硬编码位置。
3.1 CMakeLists.txt 中的版本定义机制
版本号的核心来源是根目录 CMakeLists.txt:
set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 5) set(CUTTER_VERSION_PATCH 0) set(CUTTER_VERSION "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}")围绕这一主版本号,还有两个配套机制值得发布维护者注意:
CUTTER_VERSION_SUFFIX(CMakeLists.txt):供打包者附加构建号或补丁标识,例如 RPM 包名与源码版本相同但携带额外补丁时,可通过该变量区分。CUTTER_INCLUDE_GIT_HASH(CMakeLists.txt):默认开启,会将 git 提交哈希与分支名拼入完整版本号:
set(CUTTER_VERSION_FULL "${CUTTER_VERSION}${CUTTER_VERSION_SUFFIX}-${GIT_BRANCH}-${GIT_REV}")也就是说,构建产物显示的2.5.0-dev-abc1234这种版本串即来源于此。正式发布时需确保该机制与预期的发布版本一致(例如从 tag 检出时GIT_BRANCH会是HEAD,打包前需确认CUTTER_VERSION_FULL的最终形态)。
4. 发布候选版本(RC):打标签与创建 pre-release
以v1.11.0为例(流程文档原始示例,当前仓库版本体系为2.x,此处仅演示 tag 命名约定),RC 阶段的操作如下:
4.1 创建 RC 标签
git tag v1.11.0-rc1 git push origin v1.11.0-rc1原文档中的
git tag push origin v1.11.0-rc1应为git push origin,属于笔误;正确写法是先git tag再git push origin <tagname>。另外注意当前仓库的版本体系已演进为2.x(见 CMakeLists.txt),实际打标签时应使用真实的版本号。
4.2 创建 GitHub Release(pre-release + 草稿)
- 在 GitHub Releases 页面创建 Release;
- 标记为 pre-release(预发布),保存为 draft(草稿);
- 将 tag 设置为
v1.11.0-rc1。
先存为草稿的目的是:在打包产物尚未全部完成、测试尚未通过之前,不让 RC 面向普通用户公开;打包完成后、确认无误后再编辑并正式发布草稿。
4.3 等待各平台打包产物
Release 创建后,CI 流水线会为 Windows、macOS、Linux 等平台构建安装包。此阶段需要等待打包完成,随后进入全平台测试。
5. 回归测试:Basic testing procedure
流程文档明确指出,这不是穷尽式测试,而是一组「确保没有严重损坏」的快速冒烟检查;建议在多个不同偏移量处重复操作并随意点击,以提高发现偶发性问题的概率。测试项如下:
| 测试项 | 操作要点 | 预期结果 |
|---|---|---|
| 打开简单可执行文件 | 如/bin/ls或calc.exe | 正常加载 |
| 布局升级 | 打开应用检查界面布局 | 升级后的布局未被破坏 |
| 反汇编视图 | 打开 Disassembly widget | 显示正确的反汇编 |
| 内置插件:rzghidra | 打开反编译器并选择ghidra | 至少对部分函数显示 C 代码 |
| 内置插件:rzdec | 在反编译器中选择 rzdec | 正常显示反编译代码 |
| 样例 Python 插件 | 加载 sample python plugin | 正常工作 |
| 调试器 | 在main下断点 → 开始调试 → 通过函数列表跳转到 main | 重定位正确,看到代码而非未映射内存,断点位于预期位置;继续执行能命中main断点 |
| 干净启动 | 删除 Cutter 设置文件后启动 | 全新启动正常,布局未损坏 |
5.1 测试项对应的仓库依据
- rzghidra 为默认反编译器:在 DecompilerWidget.cpp 中,若用户未选择过反编译器,代码会将
ghidra设为默认项,这解释了为何测试清单把「打开 decompiler 并选择 ghidra」列为首要插件测试项。 - 打包选项开关:
CUTTER_PACKAGE_RZ_GHIDRA、CUTTER_PACKAGE_RZ_LIBYARA、CUTTER_PACKAGE_RZ_SILHOUETTE、CUTTER_PACKAGE_JSDEC等选项定义于 CMakeLists.txt,对应打包阶段是否编入各类 rizin 插件。 - 样例插件:C++ 样例位于 src/plugins/sample-cpp/,Python 样例位于 src/plugins/sample-python/sample_python.py,是测试插件机制的现成素材。
5.2 测试失败时的处理路径
若发现重大问题:
- 在 issue 跟踪器中提交 issue;
- 在dev 分支修复,然后cherry-pick 到 release 分支(不要直接在 stable 上改);
- 若改动量足够大,则回到第 3 步(版本锁定)重新走一遍流程,并递增 RC 编号(
rc1→rc2→ …)。
6. 正式发布:版本号、标签与 Release Notes
RC 全部通过测试后,进入正式发布阶段:
6.1 正式版本号与标签
- 将版本号更新为正式版本(如
1.11.0),同步更新第 3 节列出的所有文件; - 创建正式标签(如
v1.11.0); - 创建正式 Release。
6.2 编写 Release Notes
Release Notes 是整个发布流程中最需要「内容运营功底」的环节,文档给出的指导原则非常具体:
- 尽早开始撰写:不必等发布时才写,可在发布过程中持续积累素材;
- 对比分支差异:将当前 dev 分支与上一次发布进行比较,找出全部变更;
- 只挑最重要的:不要重复 commit log,Release Notes 是给「不想读完整提交历史的人」看的摘要;
- 按主题分组:使用类似"New features"(新特性)、"Bug Fixes"(缺陷修复)、"Decompiler"(反编译器)、"Rizin"等标题对相关变更分组,让读者能快速定位自己关心的领域。
6.3 公告与里程碑收尾
- 准备发布公告推文,并发送到 Telegram 群组、reddit 等社区渠道;
- 若本次发布对应有 GitHub milestone,在发布完成后关闭该 milestone。
7. Bugfix 发布流程
Bugfix 发布(补丁版本)与常规流程相似,但有两个关键差异:
- cherry-pick 而非合并:将必要的 bugfix 从 devcherry-pick 到 stable,只挑选修复,不带入新功能;
- 递增第三位版本号:
x.y.n→x.y.(n+1),即补丁版本只改 patch 位(例如2.5.0→2.5.1),对应 CMakeLists.txt 中的CUTTER_VERSION_PATCH变量。
其余步骤(翻译同步、版本号全仓库更新、打标签、创建 Release、测试)与正式发布一致。
8. 发布流程速查清单
| 阶段 | 关键动作 | 命令 / 文件 |
|---|---|---|
| 翻译 | 合入 Crowdin 自动 PR,更新子模块 | git submodule update translations,见 deploy_translations.sh |
| 冻结 | dev 合并进 stable;rizin 子模块指向对应分支 | git merge |
| 锁定 | 锁定 rzghidra / rzdec 为 tag 或 commit | dist/CMakeLists.txt 中的GIT_TAG |
| 版本号 | 全仓库搜索旧版本号并同步更新 | CMakeLists.txt、docs/conf.py、src/re.rizin.cutter.appdata.xml 等 |
| RC | 打标签 + pre-release 草稿 | git tag vX.Y.Z-rcN&&git push origin vX.Y.Z-rcN |
| 测试 | 全平台执行 Basic testing procedure | 见第 5 节清单 |
| 正式发布 | 更新正式版本号、创建 Release、填写分组 Release Notes | GitHub Releases |
| 公告 | 推文、Telegram、reddit 等渠道;关闭 milestone | — |
| Bugfix | dev 中 cherry-pick 到 stable,patch 位 +1 | git cherry-pick |
9. 结语
Cutter 的发布流程是一套典型的「双分支 + 子模块 + 版本锁定 + RC 迭代」开源桌面应用发布工程实践:translations 子模块保证了多语言同步的自动化,dev/stable 分支分离实现了功能冻结与持续开发并行,rzghidra 等插件版本锁定确保了发布产物的可复现性,而「全代码库版本号同步 + RC 草稿 + 冒烟测试清单」则把人为失误的概率降到最低。对于维护者而言,遵循本文梳理的 14 步流程与 Bugfix 变体,即可稳定、可预测地完成每一个版本的交付。
提示:发布流程属于维护工程范畴,实际执行时请以当前仓库的 CI 配置(如
.github/workflows、appveyor.yml等是否存在)、CMakeLists.txt 中的实际版本号(当前为2.5.0系列)以及 release-procedure.rst 的最新修订为准,避免沿用文档中已过时的文件路径与版本示例。
【免费下载链接】cutterFree and Open Source Reverse Engineering Platform powered by rizin项目地址: https://gitcode.com/gh_mirrors/cu/cutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考