ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

INAV 发布分支前移合并实战:把 release/9.1 合入 maintenance-10.x 的正确流程,以及为何禁用 GitHub “Resolve conflicts“ 按钮

INAV 发布分支前移合并实战:把 release/9.1 合入 maintenance-10.x 的正确流程,以及为何禁用 GitHub “Resolve conflicts“ 按钮
  • 无人机
  • 嵌入式
  • 智能硬件

【免费下载链接】inav

INAV: Navigation-enabled flight control software

项目地址:https://gitcode.com/gh_mirrors/in/inav
点击查看免费下载

本文基于 INAV 官方开发文档 merging-release-into-next-version.md 展开,讲解 INAV 维护者将某个发布分支(如release/9.1)的全部变更带入更新的维护分支(如maintenance-10.x)时的完整操作规范:五步式 Git 工作流、冲突解决要点、GitHub PR 自动化闭环,以及为什么绝不能用 GitHub 的 "Resolve conflicts" 按钮。读完本文,你将掌握一套保证变更流向正确(旧版本 → 新版本)、不污染老发布分支、且全程可评审的前移合并方案,并能理解每一步背后的 Git 拓扑原理。

一、背景:INAV 的版本分支模型决定了"前移合并"必须小心

INAV 采用基于版本号的分支策略(见 Development.md 的 "Branching and release workflow" 一节):

  • 当前版本维护分支(如maintenance-9.x):承载向后兼容的修复与新特性,未来的 9.1、9.2 等版本都从它发布;
  • 下一主版本分支(如maintenance-10.x):承载破坏性变更,未来的 10.0 从它发布。当前仓库检出状态也印证了这一点——CMakeLists.txt 中版本号已为project(INAV VERSION 10.0.0),且该镜像检出的正是maintenance-10.x分支;
  • master:不直接开发,维护者定期把当前维护分支合入其中仅作兜底,整个前移合并流程与master无关。

一个典型的发布周期是:在维护分支上开发 → 切出发布分支(如release/9.1)并打 RC 标签 → RC 期间的 bug 修复继续落在维护分支,而发布分支上积累的修复在发布收尾后需要整体带回下一主版本分支。这正是本文主题文档定义的场景:

Use this procedure when:you want to carry a release branch's changes forward into a newer maintenance branch (e.g.release/9.1intomaintenance-10.x, or any older branch into a newer one).

该流程也是 release-create.md "Carrying a Release Branch Forward" 一节明确指向前移合并文档的操作,并且被 nightly-build.yml 的触发分支列表佐证——当前 CI 的 nightly 构建同时监听maintenance-9.x、maintenance-10.x和release/9.1,说明发布分支与维护分支并行存活、必须保持双向内容一致。

二、五步正确工作流(完整命令可复制)

以下命令完整继承自官方文档,upstream指 INAV 主仓库的远程名(配置方式见 Development.md:git remote add upstream ...)。

第 1 步:从目标(更新的)分支出发

git fetch upstream git checkout maintenance-10.x git pull upstream maintenance-10.x

一切操作的起点是新分支,而不是旧发布分支——这是整套流程的方向基石。

第 2 步:从目标分支切出评审分支

git checkout -b merge/9.1-into-10.x

注意:必须从maintenance-10.x切出,而不是从release/9.1切出。文档特别强调:"This is the key difference from what GitHub's conflict resolver does."(这正是与 GitHub 冲突解决器的本质区别。)

第 3 步:把旧分支合并进来

git merge upstream/release/9.1

若无冲突,Git 会自动生成合并提交。若有冲突,文档给出两条硬性纪律:

# For each conflicting file, edit it directly — fix only the specific lines # Do NOT copy the entire file from either branch git add src/main/flight/servos.c # (repeat for each resolved file) git commit
  • 逐个文件、逐行手工解决,只修冲突的具体行;
  • 禁止整体复制任一分支的整个文件(等价于盲目--ours/--theirs)。

合并提交最终落在merge/9.1-into-10.x上,release/9.1自始至终不被触碰。

第 4 步:推送并开 PR

git push upstream merge/9.1-into-10.x

然后打开 PR:merge/9.1-into-10.x→maintenance-10.x。由于所有冲突已在第 3 步本地解决,这个 PR 不会有任何冲突标记,评审人可以在 GitHub UI 中正常审查、正常合并——冲突解决过程本身也进入了代码评审范围,而不是在网页按钮里悄悄完成。

第 5 步:GitHub 自动关闭原始 PR

当maintenance-10.x包含了该合并提交后,GitHub 会检测到release/9.1的所有提交都已从maintenance-10.x可达,从而自动把原先那个release/9.1→maintenance-10.x的 PR 标记为已合并并关闭。文档补充了兜底措施:如果没有自动关闭,就手动关闭它,并留下注释链接到合并 PR,避免两个 PR 悬挂造成状态混乱。

三、为什么这样设计:变更流向的 Git 拓扑

文档给出的拓扑图说明了全部要点——合并提交出现在新分支一侧,旧分支纹丝不动:

maintenance-10.x: ... ── A ── B ──────────────── M ← merge commit lands here \ / merge/9.1-into-10.x: \── (conflicts resolved here) \ release/9.1: ... ── C ── D ── E ← completely unchanged

这与 Development.md "Propagating Changes Between Branches" 一节的总规则完全一致:变更只能在低版本流向高版本(older → newer);反向合并(把新分支合入旧分支)"永远不做",因为它会把数月的较新开发拖进一个已经封版的老发布分支。

四、为什么绝对不能用 GitHub 的 "Resolve conflicts" 按钮

这是本文档最核心的警告。GitHub 官方文档的表述是:

"When you resolve a merge conflict on GitHub, theentire base branchof your pull request is merged into the head branch."

对一个release/9.1→maintenance-10.x的 PR 而言:

  • base(基底)=maintenance-10.x,head(头)=release/9.1;
  • 点击 "Resolve conflicts" 后,GitHub 会把整个maintenance-10.x合入release/9.1——方向完全反了。

其后果是灾难性且隐蔽的:生成的提交名为 "Merge branch 'maintenance-10.x' into release/9.1",看起来像一次例行操作,但实际上已把一个正在封版发布的旧分支污染进了数月的较新开发内容(新增特性、MSP 协议变更、EEPROM 布局变化等)。Development.md 在 "Force pushing" 与 "Propagating Changes Between Branches" 中也两次呼应了这一禁令,并特别指出该按钮"无条件"地产生错误方向的合并——不管使用者多么小心。上文五步流程通过"从目标分支切评审分支 + 本地解决冲突 + PR 回灌目标分支",从机制上保证release/9.1永远不接收任何提交。

五、冲突解决实操要点:INAV 仓库中的高风险文件

文档要求"逐行修复"并非泛泛之谈。结合 Development.md 的 "Generated files that must be regenerated before pushing" 与 "Resolving merge conflicts" 两节,前移合并时的冲突处理需要特别注意 INAV 的生成文件:

源文件变化需重新生成的输出CI 是否强制
src/main/fc/settings.yamldocs/Settings.md是 — docs.yml 会与重新生成的副本做 diff,过期即失败
src/main下枚举头或 msp_messages.jsoninav_enums.json、inav_enums_ref.md、README.md部分 —msp.yml会 diffREADME.md

由此产生的实操规则:

  1. 不要盲目git checkout --ours/--theirs。这两个标志会静默丢弃一侧全部改动。正确做法是先理解相对公共祖先各自改了什么:git diff <merge-base> <branch> -- <file>,再构造同时保留双方意图的解决方案。
  2. 对inav_enums.json这类文件若机械用了--theirs,历史上曾静默丢掉真实的 message/enum 条目——必须拿合并后的真实源码(MSP handler 看 fc_msp.c、枚举看对应头文件)交叉核对,必要时用src/utils/gen_msp_docs.sh重新生成。
  3. 文档示例中作为冲突文件出现的 src/main/flight/servos.c 属于飞行核心代码,解决冲突后应确认--theirs侧的 9.1 修复没有覆盖新分支已重构的 API 签名。

六、流程定位:它与 INAV 发布管线的关系

从 release-create.md 可以看出,前移合并是"发布收尾"环节的一环:

  • 发布主流程遵循"先验证构建、后打标签"原则(验证 nightly 构建产物 → 更新 SITL → 手工测试 → 才打 tag 创建 GitHub Release);
  • 发布分支(如release/9.1)在 RC/发布期间独立存在,其中的修复最终通过本文流程带往maintenance-10.x,而不是等 10.0 发布后再回溯 cherry-pick;
  • 对单个提交的传播用git cherry-pick(Development.md 给出了具体命令),对整个发布分支的传播才走本文的五步合并流程;
  • 热点修复(Hotfix)走另一条路:从发布 tag 切 hotfix 分支、补丁号 +1、按常规流程发布。

七、要点自检清单

执行前移合并前,可对照以下清单(均来自文档与 CI 配置事实):

  1. 起点是否为更新的目标分支(maintenance-10.x)并已git pull到最新?
  2. 评审分支是否从目标分支切出,命名形如merge/9.1-into-10.x?
  3. git merge upstream/release/9.1的冲突是否逐文件、逐行解决,且未整体复制任一侧文件?
  4. 生成文件(docs/Settings.md、docs/development/msp/下的枚举/文档 JSON)是否已用对应脚本重新生成并核对源码?
  5. PR 方向是否为merge/9.1-into-10.x→maintenance-10.x,且该 PR 无冲突、可正常评审?
  6. 合并后是否确认 GitHub 已自动关闭原始release/9.1→maintenance-10.x的 PR(否则手动关闭并留注释)?
  7. 全程release/9.1的 HEAD 是否保持不变?master是否完全未被涉及?

只要变更流向保持"旧 → 新"、老发布分支零污染、评审路径完整,这套流程就能安全地把一个发布周期的全部成果带入下一主版本,为 INAV 10.0 系列的后续迭代保留完整的修复历史。

  • 无人机
  • 嵌入式
  • 智能硬件

【免费下载链接】inav

INAV: Navigation-enabled flight control software

项目地址:https://gitcode.com/gh_mirrors/in/inav
点击查看免费下载

相关推荐

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进