项目管理

用需求编号、Commit 与 Git 串联完整研发流程

2026-08-22 #Git#Commit规范#研发流程#Submodule#项目管理

研发流程真正需要解决的,不只是“代码如何提交”,而是任何一次线上变更都能回答五个问题:为什么改、谁改的、改了什么、如何验证、出了问题怎样回退。

一种简单而有效的方法,是把项目管理系统中的需求编号或 Bug 编号作为贯穿整个研发流程的关联键。

一条贯穿研发流程的主线

假设项目管理系统中存在以下事项:

  • 需求:REQ-1428,增加订单导出功能;
  • 缺陷:BUG-2381,修复导出文件中金额精度错误。

编号会依次出现在分支、Commit、Pull Request、测试记录、构建产物和发布记录中:

1
2
3
4
5
6
7
需求或 Bug
→ 开发分支
→ Commit
→ Pull Request / Merge Request
→ CI 与测试报告
→ 发布版本
→ 线上监控与复盘

这样无论从项目管理系统、代码仓库还是线上版本出发,都能反向找到完整上下文。

Commit 信息规范

推荐采用下面的格式:

1
2
【需求编号】- 增加xxx
【Bug编号】- 修复xxx

实际示例:

1
2
【REQ-1428】- 增加订单导出功能
【BUG-2381】- 修复导出金额精度错误

如果团队希望继续区分变更类型,可以扩展为:

1
2
3
【REQ-1428】feat: 增加订单导出功能
【BUG-2381】fix: 修复导出金额精度错误
【TECH-0362】refactor: 拆分订单查询与导出逻辑

编号负责连接项目管理系统,feat、fix、refactor 等类型负责生成变更日志和版本统计。两者承担不同职责,可以同时保留。

一条好 Commit 应该表达什么

标题说明结果,正文解释原因、关键方案和验证方式:

1
2
3
4
5
6
【BUG-2381】fix: 修复导出金额精度错误

原因:导出层将 Decimal 转换为 float,导致部分金额出现精度损失。
处理:导出数据全程使用 Decimal,并统一保留两位小数。
验证:补充边界金额单元测试,抽查导出文件与数据库记录一致。
影响:仅涉及订单导出,不修改订单存储数据。

避免使用“修改一下”“优化代码”“修复问题”这类无法独立理解的描述。

分支命名规范

分支名建议同时表达事项类型、编号和简短主题:

1
2
3
4
git switch -c feature/REQ-1428-order-export
git switch -c bugfix/BUG-2381-export-amount
git switch -c refactor/TECH-0362-order-query
git switch -c hotfix/BUG-2401-payment-timeout

推荐类型:

类型 使用场景
feature/ 新需求或功能
bugfix/ 普通缺陷修复
hotfix/ 需要紧急发布的线上故障
refactor/ 不改变外部行为的重构
chore/ 依赖、构建或工程配置

分支应保持短生命周期。一个分支只处理一个事项,避免把多个需求混进同一个 Pull Request。

从领取任务到发布的完整流程

1. 需求准备

需求进入开发前至少具备:

  • 唯一编号、目标和业务价值;
  • 明确范围与不做事项;
  • 可验证的验收标准;
  • 接口、数据、权限和兼容性影响;
  • 发布方式与回滚条件。

缺陷还应包含复现步骤、期望结果、实际结果、环境和必要日志。

2. 创建分支

1
2
3
git switch main
git pull --ff-only
git switch -c feature/REQ-1428-order-export

--ff-only 可以避免拉取时意外生成合并提交。如果团队使用 rebase 工作流,也应在团队规范中统一说明。

3. 小步提交

先检查变化,再选择性暂存:

1
2
3
4
5
git status
git diff
git add -p
git diff --cached
git commit -m "【REQ-1428】feat: 增加订单导出接口"

git add -p 可以逐块选择变更,防止调试代码、格式化噪声或无关文件混入 Commit。

一个 Commit 应保持逻辑完整:代码、必要测试和相关文档一起提交,同时确保它可以独立通过构建。

4. 提交 Pull Request

PR 标题继续携带编号:

1
【REQ-1428】增加订单导出功能

PR 描述建议包含:

  • 关联事项与背景;
  • 方案概述和关键取舍;
  • 数据库、接口或配置变化;
  • 测试范围和验证证据;
  • 风险、监控指标与回滚方式;
  • 页面或交互变化截图。

5. CI 与评审门禁

合并前至少执行:

  • 格式检查与静态分析;
  • 单元测试和必要的集成测试;
  • 依赖和安全扫描;
  • 构建可部署产物;
  • Commit 或 PR 编号格式校验;
  • 至少一名非作者评审通过。

高风险变更可以要求架构、数据库或安全负责人追加评审。

6. 发布与回溯

构建产物应记录 Git Commit SHA,并在发布记录中写入关联编号:

1
2
3
4
5
6
版本:v2.8.0
Commit:4f37c2a
事项:REQ-1428、BUG-2381
环境:production
验证:订单导出成功率、接口延迟、错误率
回滚:恢复 v2.7.3 镜像,不执行数据回滚

出现线上问题时,可以从版本找到 Commit,再从 Commit 找到编号、PR、测试证据和负责人。

自动校验 Commit 格式

团队可以在 CI 中校验标题。以下正则接受需求、Bug 和技术任务编号:

1
^【(REQ|BUG|TECH)-[0-9]+】(feat|fix|refactor|docs|test|chore|perf|ci): .+

一个简单的 Shell 检查示例:

1
2
3
4
5
6
7
message="$(git log -1 --pretty=%s)"
pattern='^【(REQ|BUG|TECH)-[0-9]+】(feat|fix|refactor|docs|test|chore|perf|ci): .+'

if ! printf '%s' "$message" | grep -Eq "$pattern"; then
echo "Commit 格式错误:$message"
exit 1
fi

本地 Hook 可以尽早反馈,但真正的强制校验应放在服务端或 CI,因为客户端 Hook 可以被跳过。

Git 常用命令速查

查看状态和历史

1
2
3
4
5
6
git status
git log --oneline --graph --decorate --all
git show <commit>
git diff
git diff --cached
git blame <file>

分支操作

1
2
3
4
5
git branch --all
git switch <branch>
git switch -c <new-branch>
git branch -d <merged-branch>
git fetch --prune

暂存与提交

1
2
3
4
5
git add <file>
git add -p
git restore --staged <file>
git commit
git commit --amend

--amend 会重写最近一次 Commit。已经推送且多人使用的分支,不应随意改写历史。

临时保存工作

1
2
3
4
git stash push -m "REQ-1428 未完成的导出页面"
git stash list
git stash show -p stash@{0}
git stash pop

撤销和恢复

1
2
3
4
5
6
7
8
# 丢弃工作区中某个文件的未提交修改
git restore <file>

# 创建一个反向 Commit,适合已经共享的历史
git revert <commit>

# 查找误删分支或重写前的 Commit
git reflog

不要在不理解影响时使用 git reset --hard 或强制推送。共享分支优先使用 git revert 保留可审计历史。

同步主分支

1
2
3
4
5
git fetch origin
git rebase origin/main

# 或采用合并策略
git merge origin/main

团队应统一选择 rebase 或 merge 策略。不要为了“历史好看”反复重写已经进入共享分支的 Commit。

查找问题来源

1
2
3
4
5
git log -S "关键代码" --oneline
git log --grep="BUG-2381" --oneline
git bisect start
git bisect bad
git bisect good <known-good-commit>

git bisect 可以通过二分法定位引入问题的 Commit,配合自动化测试效果更好。

Git Submodule 的适用场景

Submodule 是嵌入在主仓库中的独立 Git 仓库。主仓库不直接保存它的全部内容,而是记录子仓库的一个确定 Commit。

适合场景:

  • 多个项目共享但需要独立发布的 SDK;
  • 主项目需要锁定第三方源码的确定版本;
  • 权限、发布节奏或历史必须独立的模块。

如果模块必须与主项目频繁原子修改,Monorepo、包管理器或制品仓库通常更简单。

添加 Submodule

1
2
3
4
git submodule add https://git.example.com/team/common-sdk.git libs/common-sdk
git status
git add .gitmodules libs/common-sdk
git commit -m "【TECH-0412】chore: 引入 common-sdk 子模块"

该操作会创建或更新 .gitmodules,同时让主仓库记录子模块当前 Commit。

克隆包含 Submodule 的项目

推荐一次性递归克隆:

1
git clone --recurse-submodules https://git.example.com/team/app.git

如果已经普通克隆:

1
git submodule update --init --recursive

其中 init 根据 .gitmodules 初始化本地配置,update 检出主仓库记录的 Commit,recursive 继续处理嵌套子模块。

更新 Submodule

按主仓库锁定版本更新

切换分支或拉取主仓库后执行:

1
2
git pull --ff-only
git submodule update --init --recursive

这不会自动追踪子模块远端最新版本,而是恢复到主仓库记录的确定 Commit,因此构建具备可复现性。

主动升级到子模块新版本

1
2
3
4
5
6
7
8
cd libs/common-sdk
git switch main
git pull --ff-only
cd ../..

git status
git add libs/common-sdk
git commit -m "【TECH-0415】chore: 升级 common-sdk 版本"

主仓库中的这次 Commit 记录的是新的子模块 Commit 指针。

也可以根据 .gitmodules 中配置的分支执行:

1
2
3
git submodule update --remote --merge libs/common-sdk
git add libs/common-sdk
git commit -m "【TECH-0415】chore: 升级 common-sdk 版本"

升级后必须提交主仓库中的指针变化,否则其他开发者和 CI 仍会使用旧版本。

修改 Submodule 自身代码

进入子模块后,它就是一个独立仓库:

1
2
3
4
5
6
7
cd libs/common-sdk
git switch -c feature/REQ-1502-export-helper

# 修改、测试并提交
git add -p
git commit -m "【REQ-1502】feat: 增加导出格式化工具"
git push -u origin feature/REQ-1502-export-helper

子模块 PR 合并后,回到主仓库更新并提交指针:

1
2
3
4
5
6
7
cd libs/common-sdk
git switch main
git pull --ff-only
cd ../..

git add libs/common-sdk
git commit -m "【REQ-1502】chore: 更新 common-sdk 引用"

因此一次跨仓库需求通常有两组 Commit 和 PR,它们应引用同一个需求编号。

Submodule 常见问题

子模块目录为空

1
git submodule update --init --recursive

显示 modified content

先查看子模块内部状态:

1
2
git -C libs/common-sdk status
git diff --submodule

确认是未提交修改、未跟踪文件,还是当前 Commit 与主仓库记录不一致。

修改了仓库地址

更新 .gitmodules 后同步本地配置:

1
2
git submodule sync --recursive
git submodule update --init --recursive

子模块处于 detached HEAD

git submodule update 检出固定 Commit 时出现 detached HEAD 是正常现象。若要开发子模块,先显式切换或创建分支:

1
git -C libs/common-sdk switch main

查看所有子模块版本

1
2
git submodule status --recursive
git submodule foreach --recursive 'git status --short --branch'

团队使用 Submodule 的约定

为了避免“我本地能运行,CI 却缺代码”,建议统一以下规则:

  1. CI 克隆必须启用递归 Submodule;
  2. 子模块升级和主仓库指针更新分成清晰 Commit;
  3. 子模块 Commit 必须已推送,主仓库才能引用;
  4. 不直接在 detached HEAD 上开发;
  5. 发布记录同时列出主仓库与关键子模块 SHA;
  6. 修改 .gitmodules 后执行并记录同步步骤;
  7. 定期检查失效地址、权限和长期未升级依赖。

最终落地模板

一次需求可以按下面的最小模板执行:

1
2
3
4
5
6
7
8
事项:REQ-1428
分支:feature/REQ-1428-order-export
Commit:【REQ-1428】feat: 增加订单导出功能
PR:【REQ-1428】增加订单导出功能
测试:单元测试、接口测试、导出文件人工抽查
发布:v2.8.0 / commit 4f37c2a
监控:导出成功率、P95 延迟、任务失败数
回滚:恢复上一镜像;新接口无数据迁移

规范的价值不在于让 Commit 更整齐,而在于把需求、代码、测试、发布和线上结果连接成一条可以搜索、审计和复盘的证据链。

参考资料

资料与流程复核日期:2026-08-22。团队应再以自身代码托管平台、分支保护和工作项规则为准。

评论
分享

评论