张宁的个人博客
莫道君行早,更有早行人。
好好上网
业余无线电
效率提升
软硬件知识
新能源汽车
S1:短波频率
关于
张宁的个人博客
上一篇
下一篇
汽车智能座舱软件的 Git 分支与版本管理策略
张宁的个人博客
2026-02-15
阅读 3
智能汽车
> 本文面向汽车软件开发、项目管理、软件配置管理和测试人员,介绍公共平台主线、多车型长期分支、Release 维护、Hotfix 向前同步、工程师日常操作和问题追溯。示例中的 CN、EU、SEA 分别代表中国、欧洲和东南亚项目,不对应任何特定企业或车型。 > > 本文也将实际学习过程中遇到的典型疑问整理为引用块,先呈现问题,再解释背后的 Git 机制和项目管理方法。问题表述经过归纳和通用化处理,便于读者对照自己的项目理解。 ## 目录 1. [为什么汽车软件需要完整的分支策略](#1-为什么汽车软件需要完整的分支策略) 2. [仓库、分支、Commit 和 Tag](#2-仓库分支commit-和-tag) 3. [推荐的多车型分支模型](#3-推荐的多车型分支模型) 4. [各类分支的职责和生命周期](#4-各类分支的职责和生命周期) 5. [Merge 与 Cherry-pick:公共代码如何同步](#5-merge-与-cherry-pick公共代码如何同步) 6. [Release:候选发布、正式发布和维护](#6-release候选发布正式发布和维护) 7. [Forward-port:旧版本修复如何进入新版本](#7-forward-port旧版本修复如何进入新版本) 8. [Tag 锁定的是什么](#8-tag-锁定的是什么) 9. [工程师如何确认当前分支](#9-工程师如何确认当前分支) 10. [如何确定修改应该进入哪个分支](#10-如何确定修改应该进入哪个分支) 11. [分支搞错时如何处理](#11-分支搞错时如何处理) 12. [如何防止修复遗漏和错误合并](#12-如何防止修复遗漏和错误合并) 13. [分支图、提交图和管理台账](#13-分支图提交图和管理台账) 14. [角色分工与日常工作流程](#14-角色分工与日常工作流程) 15. [常用命令及逐项解释](#15-常用命令及逐项解释) 16. [落地建议](#16-落地建议) ------------------------------------------------------------------------ ## 1. 为什么汽车软件需要完整的分支策略 汽车智能座舱项目经常同时存在一个公共平台主线、多个车型或区域项目、多个硬件配置、多个软件发布版本,以及量产后的缺陷修复和 OTA 补丁。 例如,欧洲车型 1.0 已经量产并进入维护期,同时欧洲车型 2.0 正在开发;中国车型 1.0 也在维护;公共平台主线仍在继续演进。 如果只依靠工程师记忆,容易发生: - 在错误的车型或版本分支上修改; - 将车型专属代码合并到公共主线; - 旧版本修复没有同步到新版本; - 把新功能误合并到已经冻结的 Release 分支; - 同一个问题在不同版本重复修复,甚至修复不一致; - 无法追溯交付软件对应的源代码、编译环境和测试结果。 因此,多车型项目需要的不只是 Git 命令,而是一套可执行的**分支策略、合并规则、版本基线和修复追踪机制**。 ## 2. 仓库、分支、Commit 和 Tag | 概念 | 英文 | 作用 | 是否随开发变化 | |------|------------|--------------------------------|--------------------| | 仓库 | Repository | 保存项目文件和版本历史 | 持续变化 | | 分支 | Branch | 指向一条持续演进的提交路线 | 分支指针会移动 | | 提交 | Commit | 记录一次代码变化及其父提交关系 | 提交内容不可变 | | 标签 | Tag | 为某个特定提交建立固定名称 | 正常情况下不应移动 | ### 2.1 分支不是文件夹 同一个 Git 仓库通常只有一套当前工作区文件。切换分支时,Git 根据目标分支指向的提交更新工作区。 ``` text main -> Commit A project/eu-model -> Commit A ``` 两个分支最初可以指向同一个提交。之后在车型分支上提交新功能: ``` text main -> Commit A project/eu-model -> Commit B ``` Commit A 和 Commit B 都保存在 Git 历史中。执行 `git switch main`,工作区会切换到 A 对应的文件状态;执行 `git switch project/eu-model`,工作区会切换到 B 对应的文件状态。 Git 不会因为创建分支就复制整个项目目录,也不是在每次切换时临时备份主线。已提交的版本数据保存在 `.git` 数据库中,分支只是指向提交的引用。 ### 2.2 Commit 记录的是一次变化,但对应整体快照 Commit 通常描述一次修改,例如“修复蓝牙连接超时”。但每个 Commit 对应的 Git Tree 描述的是该提交时整个仓库中已跟踪文件的目录和内容状态。 因此,Commit 不只是保存那几行改动;它可以还原该提交时仓库的完整受跟踪文件快照。 ## 3. 推荐的多车型分支模型 > **实际问题:** 一个车机平台有一个公共主线,同时存在多个车型长期分支;每个车型又有自己的 Release、Feature 和修复分支。分支越来越多后,关系像一张复杂的网络,应该如何看清整体结构?是否需要自己把所有分支和提交画在纸上? > > **本节回答:** 将“分支策略图”和“实际 Commit 历史图”分开管理。前者由项目统一定义,后者交给 Git 工具根据真实提交历史生成。  建议采用以下分支类型: - `main`:公共平台主线; - `project/*`:车型或区域长期项目分支; - `release/*`:某个车型某个软件发布系列的维护分支; - `feature/*`:新功能短期开发分支; - `bugfix/*`:开发阶段问题修复分支; - `hotfix/*`:已发布版本的维护修复分支。 ### 3.1 分支策略图 ``` text main 公共平台稳定基线 / | \ / | \ v v v project/CN project/EU project/SEA | | | feature/* feature/* feature/* bugfix/* bugfix/* bugfix/* | | | release/CN release/EU release/SEA / | \ / | \ 1.0 2.0 ... 1.0 2.0 ... | | hotfix/* hotfix/* ``` 实际分支名应明确且唯一,例如: ``` text main project/cn-model project/eu-model project/sea-model release/cn-model/1.0 release/eu-model/1.0 release/eu-model/2.0 feature/EU-1234-privacy bugfix/EU-1250-voice hotfix/EU-1300-bluetooth ``` ### 3.2 分支策略图与 Commit 历史图不是一回事 - **分支策略图**由项目或配置管理负责人维护,说明分支类型、创建来源、职责和允许的合并方向。 - **Commit 历史图**由 Git 根据真实提交关系生成,用于检查分叉、合并和提交来源。 查看真实提交图: ``` bash git log --graph --oneline --decorate --all ``` 也可以使用 GitHub 的 Insights → Network、GitKraken、Sourcetree 等工具查看。 建议:人工维护“策略”,使用工具查看“实际历史”,不要手工维护所有 Commit 的网络图。 ## 4. 各类分支的职责和生命周期 | 分支类型 | 示例 | 生命周期 | 主要职责 | 通常从哪里创建 | |----------|----------------------------|----------|------------------------|--------------------| | 公共主线 | `main` | 长期 | 公共平台代码和稳定基线 | 仓库初始化 | | 车型项目 | `project/eu-model` | 长期 | 某车型持续开发和集成 | `main` 的指定基线 | | 功能分支 | `feature/EU-1234-privacy` | 短期 | 开发一个独立需求 | 对应车型项目 | | 开发缺陷 | `bugfix/EU-1250-voice` | 短期 | 修复未发布版本的问题 | 对应项目或开发基线 | | 发布分支 | `release/eu-model/1.0` | 中长期 | 冻结、验证、发布和维护 | 车型项目 | | 维护修复 | `hotfix/EU-1300-bluetooth` | 短期 | 修复已发布版本的问题 | 对应 Release | ### 4.1 main:公共平台主线 适合进入 main 的内容包括: - 多车型共用的基础框架升级; - 通用音频、蓝牙、显示或系统服务能力; - 已确认适用于公共平台的缺陷修复; - 公共接口和通用组件优化。 不应未经评估就把某个车型专属的法规逻辑、区域配置或临时对策合并到 main。 ### 4.2 project:车型长期分支 例如 `project/eu-model` 维护欧洲车型的集成代码,包括区域配置、车型专属功能、供应商适配、系统集成和问题整改。 车型分支不是与 main 永久隔离。公共平台有新基线时,需要评估并同步到仍在开发的车型分支。 ### 4.3 feature:功能开发分支 一个功能或需求建立一个短期分支。开发完成、审核和测试通过后,合并到对应车型项目分支。不要把多个无关需求长期堆在同一个 Feature 分支中。 ### 4.4 release:发布与维护分支 车型项目达到版本冻结条件时,从项目分支创建 Release 分支,用于发布候选验证、发布缺陷修复、版本冻结、正式发布和补丁维护。 Release 分支不适合继续加入下一代大版本的新功能。 ### 4.5 bugfix 与 hotfix 的区别 | 类型 | 典型场景 | 起点 | 合入目标 | |----------|----------------------------|--------------------|------------------------------------| | `bugfix` | 开发、集成或发布前发现问题 | 项目分支或开发基线 | 对应项目或 Release | | `hotfix` | 已发布或量产版本发现问题 | 对应已发布 Release | 对应 Release,并向后续适用版本同步 | 具体命名不是 Git 强制要求,重点是团队对含义和流向形成统一约定。 ## 5. Merge 与 Cherry-pick:公共代码如何同步 > **实际问题:** 公共主线合并到某个车型分支时,是不是必须把主线的所有修改全盘合入?如果车型只需要公共主线中的某个功能或某个 BUG 修复,能否只选择其中一部分? > > **本节回答:** 整体同步公共基线通常使用 Merge;只移植明确的独立提交可以使用 Cherry-pick,但必须确认提交依赖,并记录原始提交与移植提交的关系。  公共主线合入车型分支时,不一定只能全量合入。常用方式是 Merge 和 Cherry-pick。 ### 5.1 Merge:整合一个分支相对于共同祖先的变化 假设: ``` text main: A --- B --- C --- D --- E project/eu-model: A --- B --- F --- G ``` C、D、E 是 main 上的新公共提交,F、G 是欧洲车型的独立提交。 在车型分支上执行: ``` bash git switch project/eu-model git merge main ``` Git 会以双方共同祖先为基础进行三方合并,把 main 相对于共同祖先的变化整合到当前车型分支。它不是简单复制 main 文件夹,也不是只挑选某一个功能。 适合场景: - 车型需要同步一批公共平台更新; - 公共基线升级经过评估; - 这些变化整体适用于该车型。 ### 5.2 Cherry-pick:选择特定提交移植 假设 main 上有三个独立提交: | 提交 | 修改内容 | 欧洲车型是否需要 | |--------|----------------------|------------------| | `C001` | 蓝牙通用优化 | 需要 | | `C002` | 中国车型专属导航配置 | 不需要 | | `C003` | 公共音频缺陷修复 | 需要 | 可以在车型分支上选择性移植: ``` bash git switch project/eu-model git cherry-pick C001 git cherry-pick C003 ``` Cherry-pick 通常会在目标分支上创建新的提交,因此新提交的 Commit ID 与源提交不同,但修改内容来自源提交。 需要保留来源追溯时,可以使用: ``` bash git cherry-pick -x C001 ``` `-x` 会在新提交说明中追加原始提交的来源信息。 适合场景: - 只需要某个独立公共修复; - 不适合整体升级公共基线; - 只想把少量明确的提交移植到某个版本。 ### 5.3 两种方式如何选择 | 场景 | 推荐方式 | |------------------------------------|--------------------------------------| | 项目升级到新的公共平台基线 | Merge | | 项目需要 main 上一批相互关联的更新 | 通常 Merge,并进行兼容性评估 | | 只需要一个独立公共 BUG 修复 | Cherry-pick | | 只需要某个明确功能提交 | Cherry-pick | | 旧 Release 的修复需要进入新版本 | 通常 Cherry-pick 或专门的向前移植 PR | | 多个长期分支保持共同演进关系 | 规划周期性的 Merge | 不要长期依赖大量 Cherry-pick。若车型长期只挑选 main 上的零散提交,分支历史会变复杂,容易产生重复移植、依赖遗漏和冲突。建议公共功能拆分成边界清楚、依赖明确的提交;车型定期同步公共基线;个别例外修复使用 Cherry-pick;记录原始 Commit ID 和目标分支。 Cherry-pick 只移植指定提交的改动,不会自动带入该提交依赖的其他提交。移植前必须确认依赖和适用性。 ## 6. Release:候选发布、正式发布和维护 > **实际问题:** Release/1.0 第一次发版测试失败,是否需要重新创建 Release 分支?1.0 已经正式发布并进入维护后,是否还能继续在原分支修复?同时准备 2.0 时,又应该怎样划分两个版本的工作? > > **本节回答:** 同一个版本系列的 RC 重测和补丁维护通常继续使用原 Release/1.0;下一代大版本应从车型项目分支创建新的 Release/2.0,两个发布系列各自维护。 ### 6.1 首次发版失败,可以继续使用原 Release 分支 假设欧洲车型准备发布 1.0: ``` text project/eu-model | +---- release/eu-model/1.0 ``` 第一次测试发现蓝牙、导航或音频问题,不需要重新创建 Release 分支。可以继续在原 Release 分支上修复和验证。 | Tag | 状态 | |-----------------|----------------------------| | `EU-V1.0.0-RC1` | 第一次发布候选版本 | | `EU-V1.0.0-RC2` | 修复蓝牙后的候选版本 | | `EU-V1.0.0-RC3` | 修复导航和音频后的候选版本 | | `EU-V1.0.0` | 最终正式发布版本 | RC 是 Release Candidate(发布候选版本)。每个 RC Tag 应指向不同的明确提交;不要移动已经发布的 Tag。 ### 6.2 正式发布后,Release 分支继续维护补丁版本 例如: ``` text release/eu-model/1.0 | +-- EU-V1.0.0 +-- EU-V1.0.1 +-- EU-V1.0.2 ``` 1.0 正式发布后,仍然可以继续在 1.0 Release 分支修复量产问题,形成 1.0.1、1.0.2 等补丁版本。 ### 6.3 下一代大版本应建立新的 Release 分支 1.0 维护期间,项目分支可以继续开发 2.0。待 2.0 达到冻结条件,再从项目分支创建 `release/eu-model/2.0`。 不要在 `release/eu-model/1.0` 上直接开发 2.0 的新功能。1.0 和 2.0 应有各自独立的发布和维护基线。 ## 7. Forward-port:旧版本修复如何进入新版本 > **实际问题:** Release/1.0 仍在维护补丁版本,而 Release/2.0 已经开始开发或测试。1.0 中修复的问题,怎样同步进入项目分支和 2.0,确保 2.0 正式发布时不会重新出现已经修复过的问题? > > **本节回答:** 建立 Forward-port 机制。每个修复先判断是否适用于后续版本,再通过 Merge 或 Cherry-pick 移植,并用修复同步矩阵追踪“已移植、已测试、已发布”三个不同状态。  Forward-port 通常指把旧版本中的有效修复向后续版本移植,是多版本并行维护中防止回归的重要机制。 场景: - `release/eu-model/1.0` 正在维护; - `project/eu-model` 正在开发后续功能; - `release/eu-model/2.0` 已创建并处于验证阶段; - 1.0 修复的问题也可能存在于 2.0。 ### 7.1 先判断修复是否适用于目标版本 不是所有 1.0 修复都必须进入 2.0。 | 问题 | 1.0 修复 | 2.0 是否适用 | |-----------------------|----------|---------------------------| | 公共蓝牙连接问题 | 修复 | 是,若 2.0 仍存在同一问题 | | 1.0 专属配置错误 | 修复 | 需要评估 | | 旧硬件专属 workaround | 修复 | 可能不适用 | | 公共音频内存泄漏 | 修复 | 是,若问题仍存在 | 每项修复都要经过适用性评估,不能只因为代码能合并就默认合并。 ### 7.2 从 1.0 创建 Hotfix 并完成修复 ``` bash git switch release/eu-model/1.0 git pull git switch -c hotfix/EU-1300-bluetooth ``` 修复后: ``` bash git add . git commit -m "fix(EU-1300): resolve bluetooth reconnect issue" git push -u origin hotfix/EU-1300-bluetooth ``` 经过审核和测试后,先合入 1.0: ``` text hotfix/EU-1300-bluetooth | v release/eu-model/1.0 ``` 然后发布新的补丁 Tag,例如 `EU-V1.0.1`。 ### 7.3 将修复同步到项目分支和 2.0 需要特别小心:Hotfix 分支是从 `release/1.0` 创建的。若直接把整个 Hotfix 分支 Merge 到项目分支或 2.0,可能把目标分支尚未包含的其他 1.0 Release 提交也带过去。 因此,当 Hotfix 基于旧 Release 分支创建,而目标分支已经明显分叉时,通常更稳妥的做法是把经过确认的修复提交 Cherry-pick 到目标分支。 假设修复提交 ID 为 `H1`: ``` bash # 移植到持续开发的车型项目分支 git switch project/eu-model git pull git cherry-pick -x H1 ``` 如果 2.0 Release 已经创建,也要移植到 2.0: ``` bash git switch release/eu-model/2.0 git pull git cherry-pick -x H1 ``` 然后分别完成审核、构建和测试。 Cherry-pick 会创建新的提交 ID。目标分支上的移植提交与原始 H1 应通过 `-x`、PR 描述或修复同步台账建立对应关系。 ### 7.4 如果 2.0 Release 还没有创建 这种情况更简单: 1. 先把 1.0 修复移植到 `project/eu-model`; 2. 后续从已经包含该修复的项目分支创建 `release/eu-model/2.0`。 这样新 Release 自然继承该修复。 ### 7.5 是否应该把整个 release/1.0 合并到 release/2.0? 技术上可以,但不应无条件这样做。 1.0 Release 中可能包含 1.0 专属配置、版本号调整、发布脚本、旧硬件临时对策等内容。这些不一定适合 2.0。 更推荐按修复项评估,选择性移植适用的提交。只有确认旧 Release 中所有新增变化都适用于新版本,并且团队明确希望继承整个分支历史时,才考虑整体 Merge。 ### 7.6 修复同步矩阵 | 问题编号 | 1.0 修复版本 | 原始 Commit | 是否适用 2.0 | 2.0 同步状态 | 验证状态 | |----------|--------------|-------------|----------------|--------------|----------| | EU-1300 | 1.0.1 | H1 | 是 | 已移植 | 回归通过 | | EU-1301 | 1.0.2 | H2 | 是 | 待移植 | 未验证 | | EU-1302 | 1.0.2 | H3 | 否,旧硬件专属 | 不适用 | 已评估 | 建议将状态区分为:待评估、适用待移植、已移植待测试、测试通过、已随目标版本发布、不适用(记录原因)。 **代码已合入、测试已通过、软件已发布是三个不同状态。** ## 8. Tag 锁定的是什么 > **实际问题:** Tag 到底是标记某一次 Commit,还是标记这次提交之后整个软件的状态?如果 Tag 已经用于正式车机软件发布,它能否代表最终交付的 BIN 或 OTA 软件包? > > **本节回答:** Tag 指向一个 Commit,而该 Commit 对应整个仓库当时的受跟踪文件快照;它锁定源代码基线,但不自动锁定编译环境和二进制交付物。  ### 8.1 Tag 指向一个 Commit 例如: ``` bash git tag -a EU-IVA-V1.0.0 -m "EU IVI release 1.0.0" ``` 如果当前 HEAD 指向 Commit E,那么 Tag 就指向 E。该 Commit 对应整个仓库当时的受跟踪文件快照,而不只是 E 这次修改的几行代码。 ### 8.2 Tag 不能单独保证二进制文件可重复生成 汽车软件正式交付还需要记录: | 信息 | 是否应纳入版本基线 | |----------------------------|--------------------| | Git Tag 和 Commit ID | 是 | | 源代码和受跟踪配置文件 | 是 | | 子模块具体引用 | 是 | | 编译器和工具链版本 | 是 | | 外部依赖版本 | 是 | | 编译参数和构建脚本 | 是 | | 最终 BIN / OTA 软件包 | 应归档 | | 软件包校验值(如 SHA-256) | 应记录 | | 测试报告和发布审批 | 应关联 | | 适用车型、硬件和配置 | 应记录 | 建议建立追溯关系: ``` text 车型 / 区域 / 硬件版本 | v 软件版本与 Release Tag | v Git Commit ID | v 源代码 + 配置 + 子模块引用 | v 工具链 + 依赖 + 编译参数 | v 编译产物(BIN / OTA Package) | v SHA-256 + 测试报告 + 发布审批 ``` Git Tag 锁定源代码提交;构建系统和发布档案负责锁定完整交付证据。 ## 9. 工程师如何确认当前分支 > **实际问题:** 在多个车型、多个 Release 和多个修复分支并行时,工程师如何确认自己当前在哪个分支?除了看分支名称,还需要检查哪些信息,才能避免在错误的版本基线上开发? > > **本节回答:** 不靠记忆,使用 `git status`、`git branch -vv` 和 `git log -1` 检查当前分支、工作区、远程跟踪关系和最近提交。 工程师不应靠记忆判断当前分支,而应通过 Git 状态确认。 ### 9.1 查看当前分支和修改状态 ``` bash git status --short --branch ``` 只查看当前分支名称: ``` bash git branch --show-current ``` ### 9.2 查看本地分支和远程跟踪关系 ``` bash git branch -vv ``` 示例: ``` text * feature/EU-1234-privacy abc123 [origin/feature/EU-1234-privacy] main def456 [origin/main] project/eu-model ghi789 [origin/project/eu-model] release/eu-model/1.0 jkl012 [origin/release/eu-model/1.0] ``` `*` 表示当前所在分支;方括号中的内容表示该本地分支跟踪的远程分支。 ### 9.3 查看当前分支最近一次提交 ``` bash git log -1 --oneline --decorate ``` 建议每次开始工作前执行: ``` bash git status -sb git branch -vv git log -1 --oneline --decorate ``` 分别确认当前分支、工作区状态、远程跟踪关系和最近一次提交。 ## 10. 如何确定修改应该进入哪个分支 > **实际问题:** 工程师收到一个问题修复任务后,应该先在某个分支上 Commit,再考虑提交到哪里吗?还是应该先明确目标分支?如果一个修复需要进入多个版本,应该怎样提交和审核? > > **本节回答:** 先由任务单明确首要修复目标和同步目标,再从正确基线创建工作分支。Commit 记录修改,Push 上传工作分支,PR 的 Base 明确本次修改要合入的目标分支。  正确顺序是:**先明确任务目标分支,再创建工作分支,最后 Commit 并提交 PR。** 工程师不应先随意修改和提交,再决定 Commit 应该放在哪里。 ### 10.1 任务单先明确目标 | 项目 | 示例内容 | |--------------|--------------------------------------------| | 问题编号 | EU-1300 | | 车型 | 欧洲车型 | | 软件版本 | 1.0 | | 问题类型 | 量产维护问题 | | 首要修复目标 | `release/eu-model/1.0` | | 是否向后同步 | 是 | | 其他目标 | `project/eu-model`、`release/eu-model/2.0` | ### 10.2 从正确目标分支创建任务分支 ``` bash git switch release/eu-model/1.0 git pull git switch -c hotfix/EU-1300-bluetooth ``` ### 10.3 修改、提交和推送 ``` bash git status git diff git add . git commit -m "fix(EU-1300): resolve bluetooth reconnect issue" git push -u origin hotfix/EU-1300-bluetooth ``` ### 10.4 PR 明确 Source 和 Base | PR 字段 | 示例 | 含义 | |------------------|----------------------------|------------------------| | Source / Compare | `hotfix/EU-1300-bluetooth` | 工程师开发的来源分支 | | Base | `release/eu-model/1.0` | 本次申请合入的目标分支 | PR 的 Base 是关键检查项。创建 PR 前必须确认它与任务单指定的目标一致。 如果一个修复需要进入多个版本,应为每个目标分支建立独立 PR 或移植记录,并分别审核、测试。 ## 11. 分支搞错时如何处理 > **实际问题:** 如果工程师在错误分支上修改,甚至已经 Commit 或 Push,是否还有办法纠正?应该怎样处理,才能不丢失代码,也不破坏共享分支历史? > > **本节回答:** 根据是否已 Commit、是否已 Push,分别采用 Stash、Cherry-pick 或新的 PR 纠正。共享分支上的错误修改应通过正式 Revert 或修复流程处理,避免擅自改写历史。 ### 11.1 修改了错误分支,但还没有 Commit 可以用 Stash 暂存修改,再切换到正确基线创建分支: ``` bash git stash push -u -m "temporarily save uncommitted changes" git switch release/eu-model/1.0 git switch -c hotfix/EU-1300-bluetooth git stash pop ``` `-u` 表示连未跟踪文件也一并暂存。恢复后要检查冲突和遗漏。 ### 11.2 已经 Commit,但还没有 Push 先找到错误提交的 Commit ID: ``` bash git log -1 --oneline ``` 在正确基线上创建工作分支: ``` bash git switch release/eu-model/1.0 git switch -c hotfix/EU-1300-bluetooth ``` 然后移植提交: ``` bash git cherry-pick <错误分支上的CommitID> ``` 确认正确分支的代码和测试结果无误后,再按团队规则处理原错误分支。不要急于删除原分支。 ### 11.3 已经 Push 到错误分支 建议: 1. 暂停后续修改; 2. 确认错误分支是否已经创建 PR; 3. 从正确目标分支创建新的工作分支; 4. Cherry-pick 需要的修复提交; 5. 在正确目标分支创建新的 PR; 6. 关闭错误 PR,并由仓库管理员确认是否需要清理错误分支。 如果错误修改已经进入 main 或 release,应使用正式 Revert 或修复流程处理。不要擅自使用 `reset --hard` 或 `push --force` 改写共享历史。 ## 12. 如何防止修复遗漏和错误合并 > **实际问题:** 一个公共 BUG 可能影响多个车型和多个软件版本。即使工程师在一个 Release 中修复了问题,怎样确保其他受影响版本也完成了修复、测试和发布,而不是只在台账上写了“已修复”? > > **本节回答:** 使用唯一问题编号贯穿问题单、分支、Commit、PR 和测试报告;再通过修复同步矩阵分别记录代码移植、测试通过和正式发布状态。 汽车软件项目需要把问题单、分支、Commit、PR、测试和 Release 建立关联。 ### 12.1 每个问题使用唯一编号 例如: ``` text EU-1300 COM-0021 CN-2450 ``` 编号应出现在项目管理系统问题单、Git 分支名称、Commit Message、PR 标题、修复同步记录、测试报告和发布记录中。 ### 12.2 修复同步矩阵 | 问题编号 | 首次修复分支 | EU 1.0 | EU 2.0 | CN 1.0 | |----------|-----------------|--------|--------|--------| | EU-1300 | hotfix/EU-1300 | 已修复 | 已移植 | 不适用 | | EU-1301 | hotfix/EU-1301 | 已修复 | 待移植 | 不适用 | | COM-0021 | bugfix/COM-0021 | 已同步 | 已同步 | 已同步 | 建议进一步记录原始 Commit ID、各目标分支的移植 Commit ID、PR 编号、适用性评估、构建测试结果和对应发布 Tag。 ### 12.3 PR 模板 ``` markdown ## 基本信息 - 问题编号: - 车型 / 区域: - 软件版本: - 修改模块: ## 本次修改 - 问题现象: - 根本原因: - 修改内容: ## 分支信息 - 来源分支: - 目标分支: ## 版本同步 - [ ] 是否需要同步公共主线 - [ ] 是否需要同步其他车型 - [ ] 是否需要同步其他 Release 版本 - [ ] 是否需要同步后续大版本 - 不适用的版本及原因: ## 验证情况 - [ ] 代码检查 - [ ] 单元测试 - [ ] 集成测试 - [ ] 车辆验证 ## 追溯信息 - 原始 Commit ID: - 移植 Commit ID: - 测试报告: - 目标软件版本: ``` ### 12.4 仓库保护规则 GitHub 的 Branch Protection Rules 或 Repository Rulesets 可以配置: - `main` 不允许直接 Push; - `release/*` 不允许未经审核直接 Push; - 合并必须通过 PR; - 至少一名指定负责人审批; - 自动化构建和测试通过后才能合并; - 通过 CODEOWNERS 指定模块审核人; - 保护正式发布 Tag,避免误移动或删除。 工具限制比单纯依靠工程师自觉更可靠。 ## 13. 分支图、提交图和管理台账 建议维护两类图和两张台账。 ### 13.1 分支策略图 由软件配置管理负责人维护,内容包括分支类型和命名、创建来源、合并目标、同步规则、分支负责人、生命周期和关闭条件。不需要把所有 Commit 都画进去。 ### 13.2 Commit 历史图 由 Git 根据真实提交历史生成: ``` bash git log --graph --oneline --decorate --all ``` 用于分析分支分叉、Merge、提交来源和实际代码关系。 ### 13.3 分支管理台账 | 字段 | 说明 | |--------------|------------------------------------------------------| | 分支名称 | Git 中的真实分支名 | | 分支类型 | Main / Project / Release / Feature / Bugfix / Hotfix | | 所属车型 | CN / EU / SEA 等 | | 所属软件版本 | 1.0 / 2.0 等 | | 源分支 | 从哪个分支创建 | | 目标分支 | 最终应合入哪里 | | 分支负责人 | 谁负责维护 | | 当前状态 | 开发中 / 测试中 / 已发布 / 已关闭 | | 创建时间 | 分支创建时间 | | 结束时间 | 分支关闭时间 | | 对应 Tag | 已发布版本标签 | ### 13.4 修复同步台账 | 字段 | 说明 | |-----------------|----------------------| | 问题编号 | 唯一问题 ID | | 问题描述 | 现象和根因 | | 首次修复版本 | 最早修复的 Release | | 原始 Commit | 首次修复提交 ID | | 适用车型 / 版本 | 需要评估的目标范围 | | 移植 Commit | 目标分支上的对应提交 | | PR | 对应审核记录 | | 测试状态 | 待测 / 通过 / 失败 | | 发布状态 | 未发布 / 已发布 | | 不适用原因 | 不需要移植时记录原因 | 两张台账职责不同: - **分支管理台账**回答有哪些分支、谁负责、分支关系如何; - **修复同步台账**回答某个问题在哪些车型和版本修复、测试和发布。 ## 14. 角色分工与日常工作流程 ### 14.1 角色职责建议 | 角色 | 主要职责 | |-------------------------|----------------------------------| | 软件架构师 / 平台负责人 | 定义公共主线和平台基线 | | 车型项目负责人 | 定义车型项目分支及版本计划 | | 软件配置管理员 | 维护分支策略、发布基线和同步关系 | | 模块开发工程师 | 在指定工作分支开发和提交 | | 模块负责人 | 审核代码和技术方案 | | 测试负责人 | 确认修复验证和回归测试 | | 发布负责人 | 确认 Tag、软件包和正式发布条件 | ### 14.2 工程师日常工作流程 以欧洲车型 1.0 量产问题为例: 1. 从项目管理系统获取问题编号、车型、软件版本、修复目标和同步目标; 2. 使用 `git status -sb` 确认当前分支和工作区; 3. 切换到指定 Release 基线; 4. 拉取最新代码; 5. 创建带问题编号的 Hotfix 分支; 6. 修改代码,检查 `git diff`; 7. Commit 并 Push; 8. 创建 PR,确认 Source 和 Base; 9. 通过代码审核、自动化测试和必要的车辆验证; 10. 合并到目标 Release; 11. 按适用性将修复向项目分支、其他 Release 或公共主线移植; 12. 更新修复同步台账; 13. 记录测试结果和最终发布 Tag。 ### 14.3 每次开始工作前的检查清单 ``` bash # 当前在哪个分支 git branch --show-current # 当前工作区状态 git status -sb # 本地分支及远程跟踪关系 git branch -vv # 最近一次提交 git log -1 --oneline --decorate # 所有分支的提交关系 git log --graph --oneline --decorate --all ``` ## 15. 常用 Git 命令及逐项解释 ### 15.1 查看当前分支 ``` bash git branch --show-current ``` | 片段 | 类型 | 含义 | |------------------|----------|--------------------| | `git` | 程序命令 | 启动 Git | | `branch` | 子命令 | 分支管理 | | `--show-current` | 选项 | 只显示当前分支名称 | ### 15.2 查看分支和远程跟踪关系 ``` bash git branch -vv ``` | 片段 | 类型 | 含义 | |----------|----------|--------------------------------------------------| | `git` | 程序命令 | 启动 Git | | `branch` | 子命令 | 查看分支 | | `-vv` | 选项 | 显示更详细的分支信息,包括上游跟踪分支和提交摘要 | ### 15.3 创建并切换功能分支 ``` bash git switch -c feature/EU-1234-privacy ``` | 片段 | 类型 | 含义 | |---------------------------|----------|----------------------------------| | `git` | 程序命令 | 启动 Git | | `switch` | 子命令 | 切换当前分支 | | `-c` | 选项 | create,创建分支并切换 | | `feature/EU-1234-privacy` | 参数 | 新分支名,包含功能类型和问题编号 | ### 15.4 合并主线 ``` bash git switch project/eu-model git merge main ``` | 片段 | 类型 | 含义 | |----------|--------|----------------------------------------------| | `switch` | 子命令 | 切换到车型项目分支 | | `merge` | 子命令 | 将指定分支相对于共同祖先的变化整合到当前分支 | | `main` | 参数 | 要合入的来源分支 | 注意:`git merge main` 是把 main 合并到当前分支,而不是把当前分支合并到 main。 ### 15.5 选择性移植提交 ``` bash git cherry-pick -x
``` | 片段 | 类型 | 含义 | |---------------|--------|--------------------------------| | `cherry-pick` | 子命令 | 将指定提交的改动移植到当前分支 | | `-x` | 选项 | 在新提交说明中记录原始提交来源 | | `
` | 参数 | 要移植的提交 ID | 执行前应切换到目标分支。Cherry-pick 会创建新提交,通常产生新的 Commit ID。 ### 15.6 暂存未提交修改 ``` bash git stash push -u -m "save work before branch switch" ``` | 片段 | 类型 | 含义 | |--------------|--------|---------------------| | `stash` | 子命令 | 临时保存工作区改动 | | `push` | 操作 | 创建一条 Stash 记录 | | `-u` | 选项 | 同时包含未跟踪文件 | | `-m` | 选项 | 指定 Stash 说明 | | 引号中的文字 | 参数值 | 说明本次暂存内容 | 恢复: ``` bash git stash pop ``` `pop` 尝试恢复最近一条 Stash 并移除该记录;如有冲突需要人工解决。若希望恢复后保留 Stash 记录,可以使用 `git stash apply`。 ### 15.7 查看所有分支提交图 ``` bash git log --graph --oneline --decorate --all ``` | 片段 | 类型 | 含义 | |--------------|--------|----------------------------| | `log` | 子命令 | 查看提交历史 | | `--graph` | 选项 | 使用线条显示分支和合并关系 | | `--oneline` | 选项 | 每个提交压缩为一行 | | `--decorate` | 选项 | 显示分支名、Tag 等引用 | | `--all` | 选项 | 显示所有引用可达的提交历史 | ### 15.8 重要英文词汇 | 英文 | 中文含义 | 在版本管理中的用途 | |----------------|----------------|---------------------------------------------| | Repository | 仓库 | 保存项目文件和版本历史 | | Branch | 分支 | 独立开发路线 | | Commit | 提交 | 一次版本记录 | | Merge | 合并 | 整合分支历史 | | Cherry-pick | 挑选提交 | 选择性移植某个提交 | | Rebase | 变基 | 将提交重新应用到新的基线上,可能改写提交 ID | | Tag | 标签 | 标记固定提交 | | Release | 发布 | 发布版本说明和交付附件 | | Hotfix | 紧急修复 | 修复已发布版本的问题 | | Forward-port | 向前移植 | 将旧版本修复同步到后续版本 | | Backport | 向后移植 | 将较新版本的修复移植到仍受支持的旧版本 | | Pull Request | 合并请求 | 申请将来源分支合入目标分支 | | Base | 目标基准 | PR 中接收修改的目标分支 | | Compare / Head | 来源分支 | PR 中提供修改的分支 | | Upstream | 上游跟踪关系 | 本地分支跟踪的远程分支 | | CODEOWNERS | 代码责任人规则 | 指定路径或模块的审核责任人 | | CI | 持续集成 | 自动构建、检查和测试流程 | ## 16. 落地建议 多车型项目不应把版本管理完全交给工程师个人记忆。建议分四层建立机制: | 层级 | 建设内容 | 解决的问题 | |------------------|----------------------------------------------|--------------------------| | 第一层:分支策略 | 分支类型、命名、创建来源、合并方向、生命周期 | 分支关系混乱 | | 第二层:任务关联 | 问题编号、车型、软件版本、修复目标、同步目标 | 不知道修改应该进入哪里 | | 第三层:仓库保护 | PR 审核、权限、CODEOWNERS、CI、Tag 保护 | 错误提交和未经验证的合并 | | 第四层:版本追溯 | 分支台账、修复同步矩阵、构建记录、测试报告 | 修复遗漏和交付不可追溯 | ### 16.1 推荐的管理原则 1. **分支策略由项目统一定义。** 工程师不自行创建长期分支或决定跨车型合并方向。 2. **任务单明确目标分支。** 问题单应包含车型、软件版本、首要修复目标和其他同步目标。 3. **每个任务使用独立工作分支。** 分支名包含问题编号,便于追溯。 4. **共享分支通过 PR 合并。** main 和 release 不允许未经审核的直接 Push。 5. **修复同步必须评估适用性。** 不是所有旧版本修改都应无条件进入新版本。 6. **移植记录必须可追溯。** 保存原始 Commit、目标分支移植 Commit、PR 和测试记录。 7. **代码合入不等于版本发布。** 分别记录代码、测试和交付状态。 8. **正式交付必须锁定完整基线。** Tag、Commit、工具链、依赖、构建参数、软件包校验值和测试报告应关联。 ### 16.2 最终管理流程 ``` text 项目需求 / 问题单 | v 明确车型、软件版本和修复目标 | v 创建对应 Feature / Bugfix / Hotfix 分支 | v 开发、Commit、Push | v Pull Request(明确 Source 和 Base) | v 代码审核 + 自动化构建 + 测试 | v 合并到指定 Project / Release / Main | v 评估其他车型和版本的同步要求 | v Merge / Cherry-pick / 适配修复 | v 更新修复同步矩阵 | v Tag + Release + 软件交付归档 ``` **总结:** 对于多车型、多区域、多 Release 并行的汽车智能座舱项目,Git 负责记录真实的代码历史,但它本身不会自动判断某个修复应该进入哪些车型和版本。分支策略定义代码流向,任务和 PR 明确修改目标,CI 和权限规则降低误操作风险,修复同步矩阵及发布基线负责保证问题不遗漏、交付可追溯。 真正成熟的版本管理,不是让每个工程师记住所有分支,而是让工程师在接到任务时能够明确知道:**从哪里开始、改动提交到哪里、谁来审核、还要同步到哪些版本,以及如何证明最终交付包含了正确的修改。**
文章关键词
智能座舱
软件
版本管理
主线
分支
发表评论
让交流带来新的灵感
取消回复
友善表达,认真交流