4、Git在固件版本管理中的应用:Git基础操作、分支策略(Git Flow)、Tag打标与发布、Changelog编写规范
说到固件版本管理,我敢说这是很多嵌入式团队最容易翻车的地方。你想想看,一个远程IO模块,可能同时有十几个现场在跑不同版本。没有一套靠谱的版本管理,出问题的时候你连哪个版本在哪个站点都搞不清楚。嗯,今天我们就来聊聊Git在固件管理中的那些事。
4.1 Git基础操作:别只会commit和push
很多工程师用Git,说白了就是三板斧:git add、git commit、git push。但在固件开发中,这远远不够。我在项目中遇到过好几次,因为误操作把开发中的代码合并到了发布分支,结果现场升级后模块直接罢工。
这里我列出几个固件开发中必须掌握的基础操作:
- git stash:临时保存工作区修改。比如你正在改bug,突然要切到另一个分支修紧急问题,用stash把当前改动存起来,干净利落。
- git rebase -i:交互式变基。我习惯在提交PR前用这个把多个小commit合并成一个,保持提交历史干净。
- git cherry-pick:挑拣提交。这个在固件维护中特别有用——比如你在开发分支修了一个bug,想把它同步到维护分支,用cherry-pick比合并整个分支安全得多。
- git revert:撤销某次提交。注意不是reset,revert会生成一个新的反向提交,不会破坏历史。这在多人协作时非常重要。
重要提醒:在固件仓库中,永远不要对已推送的提交执行git reset --hard。我曾经有个同事这么干过,结果团队其他人的本地仓库全乱了,花了一整天才恢复。
4.2 分支策略:Git Flow在固件中的落地
Git Flow是经典的分支模型,但很多嵌入式团队觉得它太复杂。我个人觉得,对于远程IO模块这种产品,Git Flow其实非常合适。为什么?因为固件有明确的发布周期,而且需要同时维护多个历史版本。
我建议的分支结构是这样的:
| 分支类型 | 命名规则 | 用途 |
|---|---|---|
| master | master | 只存放已发布的正式版本,每个提交对应一个发布Tag |
| develop | develop | 日常开发的主分支,所有功能分支从这里拉出 |
| feature | feature/xxx | 新功能开发,完成后合并回develop |
| release | release/v1.x.x | 发布前的测试和修bug,完成后合并到master和develop |
| hotfix | hotfix/xxx | 紧急修复已发布版本的问题,直接从master拉出 |
举个例子。假设我们正在开发远程IO模块的v2.0固件。流程是这样的:
- 从develop分支拉出feature/modbus-tcp功能分支
- 开发完成后合并回develop
- 所有功能开发完毕,从develop拉出release/v2.0.0分支
- 在release分支上只修bug,不添新功能
- 测试通过后,合并到master并打Tag v2.0.0
- 同时合并回develop,确保develop包含所有修复
我的经验:release分支上的bug修复,一定要同时合并到develop。我曾经漏掉这一步,结果develop分支一直带着那个bug,直到下一个版本才发现,白白浪费了两天排查时间。
4.3 Tag打标与发布:给固件贴上身份证
Tag在固件管理中太重要了。你想想看,一个远程IO模块可能跑了三年,现场有几十个版本。没有Tag,你根本不知道哪个commit对应哪个发布版本。
我习惯用语义化版本号来打Tag:
# 正式版本
git tag -a v2.0.0 -m "Release v2.0.0: 新增Modbus TCP支持,修复看门狗复位问题"
# 候选版本
git tag -a v2.0.0-rc1 -m "Release candidate v2.0.0-rc1"
# 紧急修复版本
git tag -a v2.0.1 -m "Hotfix v2.0.1: 修复Modbus TCP连接超时问题"
Tag命名规范我建议这样:
- v主版本.次版本.修订号:比如v2.0.0
- 候选版本加后缀:v2.0.0-rc1、v2.0.0-beta2
- 紧急修复直接递增修订号:v2.0.0 → v2.0.1
注意:Tag一旦推送,不要删除或修改。如果打错了,就打个新的。删除远程Tag会导致其他开发者的本地引用混乱,我见过因此引发的构建失败案例。
4.4 Changelog编写规范:让每个版本都有据可查
Changelog不是写给自己看的,是写给现场工程师、测试人员和客户看的。我见过太多Changelog写「修复了一些bug」这种废话,这跟没写有什么区别?
我推荐用Keep a Changelog规范,结构清晰:
# Changelog
## [v2.0.0] - 2024-03-15
### 新增
- 支持Modbus TCP协议,可同时连接8个主站
- 新增看门狗超时自动复位功能
- 增加固件升级失败后的回滚机制
### 修复
- 修复Modbus RTU模式下CRC校验偶尔失败的问题
- 修复DI通道在强电磁干扰下的误触发问题
- 修复Web配置页面在Chrome 120+版本上显示异常
### 变更
- 优化ADC采样率,从100Hz提升到200Hz
- 升级FreeRTOS内核版本至V10.5.1
### 废弃
- 废弃旧版私有协议(将在v3.0中移除)
### 安全
- 修复Web服务中的XSS漏洞(CVE-2024-xxxx)
## [v1.9.0] - 2024-01-20
### 新增
- 支持MQTT协议上报数据
- 新增远程日志功能
写Changelog的几个原则:
- 按类型分类:新增、修复、变更、废弃、安全,一目了然
- 写清楚影响范围:不要说「修复了bug」,要说「修复了DI通道在强电磁干扰下的误触发问题」
- 注明关联Issue或PR号:方便追溯
- 每个版本独立成段:按时间倒序排列
我的习惯:每次提交代码时,就在commit message里写上Changelog条目。发布前整理一下就能直接用,省得临时回忆改了什么。嗯,这个习惯帮我避免了好几次漏记重要变更的尴尬。
最后说一句,Git管理固件版本,核心不是工具本身,而是流程和规范。工具再强大,团队不遵守也是白搭。我见过太多团队,Git Flow画得漂漂亮亮,实际用起来还是一团糟。所以,定好规则,严格执行,比什么都重要。