3、版本控制策略:Git分支模型、代码审查、标签与发布管理、子模块管理

版本控制这事儿,在车载软件开发里,真不是简单的「谁改了什么」。

我见过太多团队,代码写得挺好,一合并就崩。为什么?分支策略没想清楚。今天咱们就聊聊,怎么用Git把这摊事儿理顺。

3.1 Git分支模型:选对路子,少走弯路

车载软件有个特点:硬件依赖强,版本迭代慢,但稳定性要求极高。你想想看,一个刹车控制器的代码,能随便在主分支上改吗?

所以,分支模型的选择,直接决定了你的CI/CD能不能跑起来。

3.1.1 GitFlow:适合传统车载项目

我个人习惯在大型、多版本并行的项目里用GitFlow。它结构清晰,但有点重。

  • master分支:只存发布过的代码。每次发布,打一个tag。
  • develop分支:日常开发的主战场。所有feature分支都从这拉。
  • feature分支:开发新功能。比如feature/autopilot-v2
  • release分支:准备发布时用。只修bug,不加新功能。
  • hotfix分支:线上出紧急问题,从master拉,修完合并回master和develop。

我的经验:在车载项目中,release分支特别重要。我记得有一次,一个ADAS项目要同时维护三个硬件平台的版本。没有release分支,光合并就能把人逼疯。

3.1.2 Trunk-Based:适合快速迭代的模块

说白了,Trunk-Based就是所有人都在主干上开发,或者最多拉个短期分支。适合那些频繁集成、自动化测试覆盖率高的模块。

为什么会有人用这个?因为快。没有合并地狱,没有长命分支。

  • 分支存活时间不超过一天。
  • 每次提交都要通过CI。
  • 代码审查必须快,否则阻塞别人。

注意:Trunk-Based对测试要求极高。我曾经在一个项目中强行推Trunk-Based,结果单元测试覆盖率只有30%,上线第一天就崩了。嗯,从那以后我学乖了——测试不到位,别玩主干开发。

3.1.3 我的建议:混合策略

别死磕一种模型。我现在的做法是:

  • 核心安全模块(如制动、转向)用GitFlow,严格管控。
  • 非安全模块(如娱乐系统、OTA客户端)用Trunk-Based,快速迭代。
  • 中间层(如通信中间件)用简化版GitFlow,只保留master和feature分支。

3.2 代码审查流程:不只是走个过场

代码审查,说白了就是「让别人看看你写的代码有没有坑」。但在车载领域,这步不能省。

3.2.1 审查什么?

  • 功能正确性:逻辑对不对?边界条件处理了吗?
  • 编码规范:MISRA C/C++合规吗?命名规范吗?
  • 安全相关:有没有潜在的内存泄漏?有没有未初始化的变量?
  • 测试覆盖:新代码有没有对应的单元测试?

3.2.2 审查流程

  1. 开发者提交PR,关联Jira/Redmine任务。
  2. CI自动运行:编译、静态检查、单元测试。
  3. 至少两名审查者:一个熟悉业务,一个熟悉架构。
  4. 审查者提出意见,开发者修改。
  5. 所有讨论resolve后,合并。

避坑指南:我曾经见过一个团队,审查者只看代码格式,不看逻辑。结果一个指针越界的bug在生产环境跑了三个月才被发现。所以,我建议审查时重点关注逻辑和边界条件,格式问题交给自动化工具。

3.3 标签与发布管理:给版本上个锁

标签,就是给某个commit打个标记,方便回滚和追溯。在车载软件里,标签就是你的「发布凭证」。

3.3.1 标签命名规范

类型 格式 示例
正式发布 v主版本.次版本.修订号 v2.1.0
预发布 v主版本.次版本.修订号-rc.序号 v2.1.0-rc.3
热修复 v主版本.次版本.修订号-hotfix.序号 v2.1.1-hotfix.1

3.3.2 发布流程

  1. 从develop分支拉release分支。
  2. 在release分支上修bug,打预发布标签。
  3. 通过所有测试后,打正式发布标签。
  4. 合并到master和develop。
  5. 在master上打正式标签,触发CI/CD构建。

我的经验:标签一定要和CI/CD联动。我习惯在CI脚本里加一步:检查当前commit是否有对应标签。没有标签,不允许部署到生产环境。这招帮我挡过好几次「手滑」的误操作。

3.4 子模块管理:别让依赖变成噩梦

车载软件里,子模块太常见了。比如AUTOSAR的配置、第三方库、甚至不同ECU的共享代码。Git子模块(submodule)是个好东西,但用不好就是灾难。

3.4.1 什么时候用子模块?

  • 多个项目共享同一个库(如通信协议栈)。
  • 第三方依赖需要固定版本(如某个芯片的驱动)。
  • 不同模块有独立的版本节奏。

3.4.2 常见坑与解决方案

问题 表现 解决方案
子模块指针漂移 别人拉代码,子模块版本不对 每次提交父项目时,确保子模块指针已更新
子模块修改未提交 本地改了子模块,忘了push CI中增加检查:子模块是否有未提交的修改
子模块过多 拉取代码慢,管理混乱 考虑用repo工具或Git subtree替代

注意:我曾经在一个项目中,子模块嵌套了三层。结果每次更新依赖,都要手动更新每一层的指针。后来我改用Git subtree,虽然合并时有点麻烦,但至少不会出现「子模块的子模块」这种鬼东西。

3.4.3 子模块管理最佳实践

  • 子模块尽量扁平化,不要嵌套。
  • 在README中写明子模块的用途和版本要求。
  • CI脚本中增加git submodule update --init --recursive
  • 定期清理不再使用的子模块。

好了,版本控制策略这块,说白了就是「怎么管代码、怎么审代码、怎么发代码、怎么管依赖」。你想想看,如果这四件事没做好,CI/CD再自动化也是白搭。嗯,下一章咱们聊聊自动化构建和测试的集成,那才是真正让CI/CD跑起来的关键。