分支策略:Git Flow、GitHub Flow、Trunk Based Development,哪种适合嵌入式项目?
说实话,这个问题我几乎每次培训都会被问到。
做嵌入式开发的兄弟,跟纯软件团队不一样。我们手里有硬件,有RTOS,有驱动,还有一堆编译工具链的坑。选分支策略,不能光看网上那些「最佳实践」——得看你的项目到底长什么样。
先聊聊三种主流策略
简单过一下,免得有人不熟悉。
Git Flow
经典中的经典。有 master、develop、feature、release、hotfix 五类分支。流程严谨,适合有固定发布周期的项目。
优点:结构清晰,责任分明。谁在开发新功能,谁在修紧急bug,一目了然。
缺点:分支多,合并频繁。嵌入式项目如果硬件还在改版,光合并就能让你崩溃。
GitHub Flow
极简派。只有一个 main 分支,所有开发从 main 拉出 feature 分支,做完提PR,合并回 main,立刻部署。
优点:简单,快。适合持续部署的互联网项目。
缺点:对嵌入式来说,太激进了。你想想看,固件烧进去出了问题,可不是回滚个版本就能解决的——硬件可能已经报废了。
Trunk Based Development
主干开发。所有开发者直接往 trunk(或 main)提交小改动,频繁集成。分支存活时间通常不超过一天。
优点:冲突少,集成快。适合CI/CD成熟度高的团队。
缺点:对代码质量和自动化测试要求极高。嵌入式项目里,编译一次可能就要十分钟,跑个单元测试还得接硬件——你确定能承受这种频率?
嵌入式项目的特殊性
我个人习惯,先列几个嵌入式项目跟纯软件项目不一样的地方:
- 硬件依赖:代码跑在真实硬件上,不是所有bug都能在模拟器里复现。
- 编译慢:交叉编译链,加上各种宏定义、条件编译,一次完整构建可能半小时。
- 发布周期固定:很多嵌入式产品是按季度或半年发版的,不是每天发。
- 硬件版本并行:同一个项目,可能同时维护V1.0、V1.1、V2.0三个硬件版本。
- 测试成本高:自动化测试覆盖率低,很多测试得靠人工拿着示波器测。
嗯,这里要注意——这些特殊性直接决定了哪种分支策略更合适。
我的建议:嵌入式项目首选「改良版Git Flow」
为什么不是GitHub Flow?
我在项目中遇到过,团队刚开始用GitHub Flow,觉得简单。结果有一次,硬件改版导致驱动接口全变了,所有feature分支都得重改。因为没有 develop 分支做缓冲,main 直接崩了三天。那三天,测试组的人天天来找我,说「固件烧进去就死机」。
为什么不是Trunk Based Development?
说实话,如果你的团队能做到每次提交都跑完完整的硬件在环测试,那Trunk Based Development确实香。但现实是,大多数嵌入式团队连自动化编译都没跑通。我曾经在一个项目里试过Trunk,结果每天下午四点,大家都不敢提交代码——因为一提交,CI就炸,一炸就是半小时。
所以,我推荐的是「改良版Git Flow」。
改良版Git Flow长什么样?
核心思想:保留Git Flow的结构,但砍掉不必要的分支。
| 分支 | 用途 | 嵌入式场景建议 |
|---|---|---|
master |
发布版本 | 只合并经过完整测试的release分支 |
develop |
日常开发集成分支 | 必须保留,作为缓冲 |
feature/* |
新功能开发 | 从develop拉出,开发完合并回develop |
release/* |
发布准备 | 从develop拉出,只修bug,不添新功能 |
hotfix/* |
紧急修复 | 从master拉出,修完同时合并回master和develop |
hardware/* |
硬件版本适配 | 新增分支,用于管理不同硬件版本的代码差异 |
关键点:嵌入式项目一定要加 hardware/* 分支。这是我踩过坑之后加上的。以前没有这个分支,硬件版本切换全靠宏定义,结果代码里到处都是 #ifdef HW_V1,维护起来想死。
具体怎么操作?
举个例子。假设我们正在开发一款剃须刀,硬件版本是V2.0。
# 1. 从develop拉出feature分支
git checkout develop
git checkout -b feature/blade-motor-control
# 2. 开发完成,合并回develop
git checkout develop
git merge feature/blade-motor-control
# 3. 准备发布V2.0.1
git checkout -b release/v2.0.1
# 4. 在release分支上只修bug
# 修完bug后,合并到master和develop
git checkout master
git merge release/v2.0.1
git tag v2.0.1
git checkout develop
git merge release/v2.0.1
# 5. 如果发现紧急bug
git checkout master
git checkout -b hotfix/crash-on-startup
# 修完
git checkout master
git merge hotfix/crash-on-startup
git tag v2.0.2
git checkout develop
git merge hotfix/crash-on-startup
小技巧:我习惯在 release/* 分支上只做bug fix,不做功能开发。这样release分支的代码质量可控,测试组也只需要关注这一份代码。
避坑指南
我曾经犯过一个错误——在 develop 分支上直接修bug。结果修到一半,发现这个bug跟某个feature分支的代码冲突。最后花了半天时间解冲突,还引入了新bug。
后来我定了个规矩:所有改动,不管大小,都必须走分支。哪怕只是改一个宏定义的值,也要从develop拉个分支出来改。
还有一个坑:不要频繁合并master到develop。嵌入式项目里,master上的hotfix可能跟develop上的新功能有冲突。我建议只在release分支准备发布时,才把master上的hotfix合并到develop。
警告:如果你的项目使用了Git LFS管理二进制文件(比如固件镜像、硬件原理图),一定要在分支策略里考虑LFS的存储成本。每个分支都会保存一份LFS文件的副本,分支多了,存储空间会爆炸。
什么时候可以考虑其他策略?
也不是说Git Flow就是唯一答案。我见过一些场景,其他策略反而更合适:
- 小团队(3人以下)做原型验证:用GitHub Flow就够了。分支多了反而增加沟通成本。
- 自动化测试覆盖率超过80%的成熟团队:可以尝试Trunk Based Development。但前提是,你的CI能在10分钟内完成编译+测试。
- 纯固件开发,没有硬件版本并行:可以简化分支结构,去掉
hardware/*分支。
但说实话,我做了十年嵌入式,见过的大多数项目,还是改良版Git Flow最稳。
总结一下
选分支策略,不是选「最好的」,而是选「最适合你团队当前状态的」。
嵌入式项目有它的特殊性——硬件依赖、编译慢、测试成本高。这些因素决定了我们不能照搬互联网团队的做法。
我个人习惯,先跑通改良版Git Flow,等团队成熟了,再考虑简化。别一上来就追求「极简」,那往往是给自己挖坑。
嗯,今天就聊到这儿。下一章我们讲讲版本号怎么定——别小看这个,我见过因为版本号乱标,导致产线烧错固件的事故。