本文档定义了团队在代码版本控制中使用 Git 的标准规范,涵盖提交信息、分支管理、合并策略、冲突解决及 Hotfix 流程。遵循这些规范有助于维护清晰的项目历史、提升协作效率,并为代码审查和回滚操作提供可靠依据。
一个高质量的 Commit 需要正确携带以下元信息:
| 元信息 | 说明 | 示例 |
|---|---|---|
| 作者(Author) | 代码的实际设计者,通常是编写代码的人 | Hugo Gu <hugogu@outlook.com> |
| 提交人(Committer) | 执行提交操作的人,可能与作者不同(如通过 PR 合并时) | Lucy <hugogu.bot@outlook.com> |
| 消息(Message) | 简要描述提交的内容和意图 | feat: JIRA-1234 Expose expiring time to FE |
注意:在团队环境中,区分 Author 和 Committer 有助于追溯代码的设计责任与提交操作责任。AI 辅助提交时,应将实际开发者设为 Author,AI 代理设为 Committer。
推荐采用 Conventional Commits 标准格式,使提交信息结构化、可解析:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
常用类型说明:
| 类型 | 含义 | 使用场景 |
|---|---|---|
feat |
新功能 | 新增用户可见的功能或能力 |
fix |
修复 | 修复 Bug 或问题 |
docs |
文档 | 仅文档变更,不含代码改动 |
style |
格式 | 代码格式调整(空格、分号等),不影响逻辑 |
refactor |
重构 | 代码重构,既不修复 Bug 也不添加功能 |
perf |
性能 | 性能优化 |
test |
测试 | 添加或修正测试代码 |
build |
构建 | 构建系统或外部依赖变更 |
ci |
持续集成 | CI/CD 配置文件和脚本变更 |
chore |
杂务 | 其他不修改源码或测试的变更 |
revert |
回滚 | 撤销之前的提交 |
完整示例:
feat(auth): JIRA-5678 Add OAuth2 login support
Implement OAuth2 authentication flow using Google and GitHub providers.
- Add OAuth2Client configuration class
- Implement token exchange and refresh logic
- Add unit tests for authentication service
BREAKING CHANGE: The `auth.token` configuration key is now deprecated.
Use `auth.oauth2.accessToken` instead.
Closes JIRA-5678
提交消息的核心原则是:描述"为什么"做变更,而非"做了什么"。代码 diff 已经精确记录了"做了什么",提交消息应当补充代码无法自解释的意图和目的。
以下面这个 Kotlin 代码变更为例:
data class OrderInfoDTO(
val id: UUID,
++ val expireTime: Instant,
)
❌ 不好的提交消息:
Add expireTime field to OrderInfoDTO class.
问题:这只是在复述代码 diff 的内容,没有提供任何额外信息。审查者无法判断这个字段是业务需要、技术债务还是临时方案。
✅ 更合理的提交消息:
feat: JIRA-1234 Expose order expiring time to FE for countdown UI.
优点:说明了业务目的(前端倒计时 UI)、关联了需求单号(JIRA-1234)、明确了变更意图(暴露过期时间给前端)。
在编写提交消息前,问自己以下问题:
核心原则:一个 Commit 只做一件事儿;一件事儿在一个 Commit 做完整。
以下每个事项都视为独立的工作单元,值得单独提交,不要相互混杂:
| 事项类型 | 说明 | 提交消息示例 |
|---|---|---|
| 代码重构 | 包括重命名、提取方法、格式化等不改变行为的调整 | refactor: JIRA-1234 Rename FileManager to FileStore |
| 配置变更 | 环境配置、依赖版本、构建参数等调整 | build: Upgrade Spring Boot to 3.2.0 |
| Bug 修复 | 针对特定问题的修复 | fix: JIRA-5678 Resolve null pointer in payment callback |
| 依赖升级 | 框架或库的版本升级 | build: JIRA-9012 Upgrade Jackson to 2.15.3 |
| 测试补充 | 新增或修正测试代码 | test: JIRA-3456 Add integration tests for refund flow |
| 事项 | 建议处理方式 |
|---|---|
| "Fix typo" | 如果代码尚未合并,修正有问题的那个 Commit(git commit --amend 或 git rebase -i) |
| "Fix build" | 找到导致构建失败的源头 Commit 进行修正,而不是新增一个修复 Commit |
| "Add more tests" | 如果尚未合并,与前面的"add unit test for XXX"合并为一个 Commit。除非新增测试与之前显著不同(如这次加的是 Integration Test) |
| 消息 | 问题 | 改进建议 |
|---|---|---|
fix issue |
过于模糊,无法定位具体问题 | fix: JIRA-1234 Resolve race condition in order creation |
commit code |
废话,无信息量 | 删除或合并到相关功能的提交中 |
test pipeline |
临时测试变更不应提交 | 使用本地测试或 CI 的调试功能 |
trigger build |
污染提交历史 | 使用 CI/CD 的手工触发功能 |
update / fix |
无上下文 | 至少包含变更范围和意图 |
:hammer: JIRA-1234 Rename FileManager to FileStore.
使用 emoji 前缀增强可读性,包含需求单号和清晰的变更描述。
:wastebasket: Revert commit ":hammer: JIRA-1234 Rename FileManager to FileStore."
回滚提交明确引用被回滚的提交,便于追溯。
分支的合理使用方式取决于团队分工与协作模式。不存在一种分支模型适用于所有团队。每个团队应当根据自身实际遇到的问题来制定分支策略。
同时,分支模型的高效应用往往不仅是流程合理性问题,也依赖工具链的成熟度与成员的熟练度。脱离团队状态和企业环境制定分支管理模型是不可取的。
| 维度 | TrunkFlow(主干开发) | GitFlow(分支开发) |
|---|---|---|
| 适用场景 | 单人开发、测试覆盖率高、持续发布 | 多人协作、依赖复杂、需要 QA/QE 协作 |
| 分支数量 | 少(主要维护 trunk/master) | 多(feature/develop/release/hotfix) |
| 发布频率 | 高(每天数次) | 中低(按迭代周期) |
| 协作复杂度 | 低 | 高 |
| 学习成本 | 低 | 高 |
| 回滚难度 | 依赖功能开关或快速修复 | 可通过分支隔离回滚 |
Hugo 的经验:在支付系统这类强监管、高可用的金融项目中,GitFlow 更为适用。因为需要严格的 QA 流程、版本控制和发布审批。而在内部工具或原型项目中,TrunkFlow 可以显著提升迭代速度。
TrunkFlow(主干开发)的核心理念是:所有开发者直接在主干分支(main/trunk/master)上工作,通过功能开关(Feature Toggle)控制未完成功能的可见性。
main/trunk (唯一长期分支)
│
├── Commit: feat: Add payment gateway integration [开关关闭]
├── Commit: fix: Resolve currency conversion precision
├── Commit: feat: Enable payment gateway for 10% users [开关灰度]
└── Commit: feat: Full rollout payment gateway [开关全开]
CI 不通过,不能合并到 trunk
使用功能开关控制未完成代码
小步快跑,频繁提交
GitFlow 通过多个长期分支和短期分支的组合,支持复杂的发布管理和并行开发。
master/main (生产分支)
│
├── hotfix/payment-bug (紧急修复分支)
│ └── 合并回 master & develop
│
└── develop (开发分支)
│
├── feature/auth-refactor (功能分支 A)
│ └── 合并回 develop
├── feature/report-export (功能分支 B)
│ └── 合并回 develop
└── release/v2.3.0 (发布分支)
└── 合并回 master & develop
| 分支 | 生命周期 | 来源 | 合并目标 | 用途 |
|---|---|---|---|---|
master |
长期 | - | - | 生产环境代码,每个 Commit 对应一个发布版本 |
develop |
长期 | master |
- | 开发集成分支,包含下一个版本的全部功能 |
feature/* |
短期 | develop |
develop |
新功能开发 |
release/* |
短期 | develop |
master + develop |
发布准备(版本号调整、文档更新、Bug 修复) |
hotfix/* |
短期 | master |
master + develop |
生产环境紧急修复 |
只能将工作分支合并到开发分支,不能反向合并
feature/* → develop ✓develop → feature/* ✗如果开发分支上的发布时间不确定,建议从 master 拉取工作分支
发布分支只接受 Bug 修复,不接受新功能
统一的分支命名有助于快速识别分支用途和负责人:
| 分支类型 | 命名格式 | 示例 |
|---|---|---|
| 功能分支 | feature/<ticket-id>-<brief-desc> |
feature/JIRA-1234-auth-refactor |
| 修复分支 | fix/<ticket-id>-<brief-desc> |
fix/JIRA-5678-payment-race-condition |
| 发布分支 | release/v<major>.<minor>.<patch> |
release/v2.3.0 |
| 热修复分支 | hotfix/<ticket-id>-<brief-desc> |
hotfix/JIRA-9999-fix-null-pointer |
| 重构分支 | refactor/<ticket-id>-<brief-desc> |
refactor/JIRA-3456-extract-service |
| 文档分支 | docs/<brief-desc> |
docs/update-api-reference |
注意:使用短横线
-分隔单词,避免使用下划线或驼峰命名。
在 GitFlow 模型中,合并操作需要遵循以下规范:
# 1. 确保本地 develop 是最新的
git checkout develop
git pull origin develop
# 2. 切换到功能分支,rebase 到最新 develop
git checkout feature/JIRA-1234-auth-refactor
git rebase develop
# 3. 解决冲突后,合并到 develop
git checkout develop
git merge feature/JIRA-1234-auth-refactor --no-ff
# 4. 推送 develop
git push origin develop
# 5. 删除已合并的功能分支
git branch -d feature/JIRA-1234-auth-refactor
使用
--no-ff(no fast-forward):强制创建合并提交,保留功能分支的历史完整性,便于后续追溯和回滚。
# 1. 合并到 master(标记版本)
git checkout master
git merge release/v2.3.0 --no-ff
git tag -a v2.3.0 -m "Release version 2.3.0"
# 2. 合并回 develop(同步修复)
git checkout develop
git merge release/v2.3.0 --no-ff
# 3. 删除发布分支
git branch -d release/v2.3.0
在 TrunkFlow 模型中,合并操作相对简单:
# 1. 从 trunk 创建短期分支(仅本地开发)
git checkout -b temp-auth-refactor
# 2. 开发完成后,rebase 到最新 trunk
git checkout temp-auth-refactor
git rebase main
# 3. 确保 CI 通过后,合并到 trunk
git checkout main
git merge temp-auth-refactor --squash # 或使用 PR 合并
# 4. 推送 trunk
git push origin main
CI 不通过,不能合并到 trunk — 这是 TrunkFlow 的底线原则。
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 频繁 rebase | 每天开始工作前 rebase 到目标分支最新状态 | 个人工作分支 |
| 小粒度提交 | 减少单次变更范围,降低冲突概率 | 所有场景 |
| 代码模块化 | 通过架构设计减少多人同时修改同一文件 | 架构层面 |
| 功能开关 | 未完成代码不干扰他人,减少并行修改 | TrunkFlow |
在 GitFlow 中,当个人工作分支与主分支存在冲突时:
优先使用 rebase 解决(推荐):
git checkout feature/JIRA-1234-auth-refactor
git rebase develop
# 解决冲突后
git add .
git rebase --continue
优点:维护线性、可读的变更历史,便于
git bisect定位问题。
何时不使用 rebase:
替代方案:merge 解决:
git checkout feature/JIRA-1234-auth-refactor
git merge develop
# 解决冲突后
git add .
git commit -m "merge: Resolve conflicts with develop"
Hugo 的踩坑记录:在团队 Git 熟练度参差不齐时,强制要求 rebase 可能导致更多问题。建议根据团队实际情况选择策略,并在团队内部统一规范。我们曾经因为强制 rebase 导致团队成员多次丢失代码,后来改为 merge 策略,配合清晰的合并提交消息,反而减少了问题。
Hotfix(热修复)用于紧急修复生产环境的严重问题,需要绕过正常的开发和测试流程,快速部署到生产环境。
| 条件 | 说明 |
|---|---|
| 生产故障 | 影响用户正常使用或造成资金损失 |
| 安全漏洞 | 存在被利用的风险,需要立即修复 |
| 合规要求 | 监管或法律要求的紧急变更 |
| 无法回滚 | 回滚成本高于修复成本 |
Hugo 的经验:在支付系统中,Hotfix 通常涉及资金安全问题(如重复扣款、金额计算错误)或核心链路故障(如无法完成支付)。这类问题需要在分钟级别响应。
# 1. 从 master 创建 hotfix 分支
git checkout master
git checkout -b hotfix/JIRA-9999-fix-payment-race-condition
# 2. 修复问题(最小化变更)
# ... 修改代码 ...
# 3. 提交修复
git commit -m "hotfix: JIRA-9999 Fix race condition in payment processing"
# 4. 合并到 master 并标记版本
git checkout master
git merge hotfix/JIRA-9999-fix-payment-race-condition --no-ff
git tag -a v2.3.1 -m "Hotfix: Fix payment race condition"
# 5. 合并回 develop(同步修复)
git checkout develop
git merge hotfix/JIRA-9999-fix-payment-race-condition --no-ff
# 6. 删除 hotfix 分支
git branch -d hotfix/JIRA-9999-fix-payment-race-condition
# 7. 部署到生产环境
# ... 触发 CI/CD 部署流程 ...
在传统的软件开发过程中,正常的发布周期以月计。为了能让紧急的错误修复尽快发布到生产环境,以不同于正常流程的方式部署,于是有了 Hotfix 流程。
但是随着 DevOps 理念的推广,正常发版的流程与效率已经得到了极大的提高。在 DevOps 应用比较到位的企业,基本上可以做到每天数次发版。这时 Hotfix 与正常发版的时效差别可以缩短到几分钟之内。
| 因素 | 使用 Hotfix | 使用正常发布 |
|---|---|---|
| 发布频率 | 每月或更低 | 每天数次 |
| 修复时效要求 | 分钟级 | 小时级可接受 |
| 问题严重程度 | 影响资金安全或核心功能 | 非核心功能或轻微问题 |
| 团队 DevOps 成熟度 | 低 | 高 |
| 测试自动化程度 | 低(需要人工验证) | 高(自动化测试覆盖) |
Hugo 的建议:对于发布频率已经很高的团队(每天多次),可以考虑简化 Hotfix 流程,将其纳入正常的发布流程中,通过优先级和审批机制来区分紧急程度,而不是维护两套独立的流程。这样可以减少流程复杂度和认知负担。
| 维度 | 检查项 |
|---|---|
| 功能性 | 代码是否实现了需求?边界条件是否处理? |
| 安全性 | 是否存在 SQL 注入、XSS、越权访问等风险? |
| 性能 | 是否存在 N+1 查询、大数据量全表扫描? |
| 可维护性 | 命名是否清晰?代码是否过于复杂?是否有注释? |
| 测试 | 是否包含单元测试?测试是否覆盖边界条件? |
| 规范 | 是否遵循团队的代码规范?提交信息是否规范? |
代码提交 → 静态分析 → 单元测试 → 构建 → 集成测试 → 安全扫描 → 部署
| 触发条件 | CI 动作 |
|---|---|
feature/* 推送 |
运行单元测试、静态分析 |
develop 推送 |
运行全量测试、构建镜像、部署到测试环境 |
release/* 推送 |
运行回归测试、构建发布镜像 |
master 推送 |
部署到生产环境(需审批) |
hotfix/* 推送 |
快速测试、紧急部署 |
版本号格式:MAJOR.MINOR.PATCH
| 版本位 | 递增条件 | 示例 |
|---|---|---|
| MAJOR | 不兼容的 API 变更 | 1.x.x → 2.0.0 |
| MINOR | 向后兼容的功能新增 | 1.2.x → 1.3.0 |
| PATCH | 向后兼容的问题修复 | 1.2.3 → 1.2.4 |
# 创建带注释的标签
git tag -a v2.3.0 -m "Release version 2.3.0: Add OAuth2 support"
# 推送标签到远程
git push origin v2.3.0
# 推送所有本地标签
git push origin --tags
# 删除本地标签
git tag -d v2.3.0
# 删除远程标签
git push origin :refs/tags/v2.3.0
文档维护记录
- 创建时间:2024-XX-XX
- 最后更新:2026-04-28
- 维护者:Hugo Gu
- 适用范围:团队内部所有使用 Git 的项目