Skip to content

Git Flow 与团队协作 ​

S3-031建议学进阶约 45 分钟JDK 21企业开发基础 · 工程工具与规范

1. 本节定位 ​

《Git 分支、合并与回退》 讲的是单个命令(分支、合并、回退)——那是"个人技能"。

本节讲的是一群人怎么配合用 Git——这是"团队约定":

text
个人:  我会用 git merge / rebase / reset              (S3-030)
团队:  谁在哪个分支上改什么、什么时候合、谁来看        (本节)

一个简单的判断:一个人用 Git,分支随便建;五个人用 Git,分支必须有规矩 ✓

2. 学习目标 ​

完成本节后,你应该能够:

  • 说出三种主流分支模型(Git Flow / GitHub Flow / Trunk-Based)以及各自的适用场景;
  • 画出 Git Flow 的分支流转,并说出五类分支各自的职责;
  • 说出"分支模型的本质是适配发布节奏"这一判断依据;
  • 说出一次 PR 应该包含什么,以及 Code Review 该看什么;
  • 说出分支保护的规则该怎么配(平台规则,不是口头约定);
  • 说出版本号(语义化版本)与分支的关系。

3. 前置知识检查 ​

4. 为什么需要这个知识 ​

先看一个没有规范的团队会怎样:

text
周一:小王在 main 上直接改了个 bug 并 push
周二:小李从 main 切分支开发,发现小王的改动跟自己的冲突
周三:线上出紧急问题,小张在 main 上改了,但忘了同步到"开发分支"
周四:下个版本发布——小张修的那个问题又出现了 ✗✗
周五:大家花半天梳理"现在 main 上到底是什么"

三个根因:

#根因本节的解法
1没有"谁在哪改"的约定分支模型(5.2)✓
2没有"合入前要检查"的机制PR + Code Review(5.6)✓
3规则只靠人记得平台级分支保护(5.7)✓

第三点最容易被忽略,也最致命:

"请大家不要直接推 main"这样的约定,在忙起来的时候一定会被破坏 ✗

唯一可靠的做法是"平台拒绝这个操作" ✓

5. 核心概念 ​

5.1 分支模型的本质 ​

先建立一个判断框架(这比记住某种模型更重要):

分支模型是对"发布节奏"的适配。 ✓

发布节奏需要什么适合的模型
一个月一个版本(要维护旧版本)需要"版本分支"与"发布准备分支"Git Flow ✓
随时发布(做完就上)只要"主干 + 短期分支"GitHub Flow ✓
一天多次几乎不要分支,靠开关控制Trunk-Based ✓

所以"选哪个模型"不是审美问题,而是:

text
我们多久发一次?要不要同时维护多个版本?出问题时多快需要修?
        ↓
        决定了分支该怎么组织

5.2 Git Flow:五类分支 ​

它的核心思想:用不同的分支表达"代码处于什么阶段" ✓

text
main ──────●──────────────●─────────────  生产环境(每个提交都是一个版本)
           │              ↑
           │         release/1.1(发布准备:只修 bug、改版本号)
           │              ↑
develop ───●────●───────●─────────────●──  集成分支(下一个版本的内容)
             ↑      ↑                ↑
        feature/a  feature/b    hotfix/x(从 main 切,修完合回 main **和** develop)

五类分支的职责:

分支从哪切合回哪谁改生命周期
main——无人直接改(只接受合并)永久 ✓
developmain—集成分支永久 ✓
feature/*developdevelop开发同学功能完成后删 ✓
release/*developmain + develop发布负责人发布后删 ✓
hotfix/*mainmain + develop ★值班同学修完删 ✓

⚠️ 加粗的那一行:hotfix 必须同时合回 main 与 develop ——忘了合回 develop,就是"下个版本又出现同样的 bug" ✗(这正是第 4 节周三那件事)

Git Flow 的三个优点:

优点说明
职责清晰看分支名就知道这段代码处于什么阶段 ✓
支持并行开发多个 feature 同时推进,互不干扰 ✓
支持维护旧版本可以在 release/1.0 上单独修,不影响 develop ✓

三个代价(这也是它后来被简化的原因):

代价说明
分支太多五种类型,新人容易搞混 ✗
合并路径长feature → develop → release → main——路径越长,冲突越多 ⚠️
不适合高频发布每次发布要开 release 分支、要回合,成本高 ✗

5.3 GitHub Flow:简化版 ​

text
main ──●──●────●────●────  永远可发布
        ↑      ↑
   feature/a  feature/b     (从 main 切,PR 后合回 main,**立即部署**)

规则只有三条:

规则说明
main 上的任何提交都是可部署的 ★靠 CI 保证
要改东西 → 从 main 切一个分支名字随意
PR → review → 合并 → 立即部署没有"发布分支"这一步

与 Git Flow 的对比:

Git FlowGitHub Flow
分支类型5 类2 类 ✓
合并路径长(3 跳)短(1 跳) ✓
发布版本化随时 ✓
维护旧版本✅ 可以❌ 不方便
学习成本高 ✗低 ✓

适合:SaaS、Web 应用(不需要维护多个版本、希望随时发)✓ ——这是目前大多数团队的默认选择 ✓

5.4 Trunk-Based:主干开发 ​

text
main(主干)──●──●──●──●──●──   所有人每天往主干合
                    ↑
              短期分支(存活 < 1~2 天)或直接提交
              + Feature Flag(未完成的功能用开关关掉)★

核心:分支存活时间越短越好 ✓

实践说明
小步提交每次改动都很小(几小时的工作量)✓
每天至少合入主干一次避免长期分支 ✗
未完成的功能靠 Feature Flag 关掉 ★这样"未完成"也能安全地待在主干上 ✓
强 CI每次合入都要跑完测试 + 能部署 ✓

为什么它能工作:

"合并痛苦"与"分支存活时间"是超线性关系 ✓

分支存活 1 天 → 合并几乎无冲突;存活 1 个月 → 冲突成灾 ✗

所以解法不是"更好地解决冲突",而是"让分支别活那么久" ✓

5.5 三者怎么选 ​

维度Git FlowGitHub FlowTrunk-Based
分支数5 类2 类1 主干 + 极短分支
发布频率版本化(周/月)随时持续
维护多版本✅❌❌
合并成本高 ✗低 ✓最低 ✓
需要 Feature Flag❌⚠️ 有时✅ 必须
CI 要求中高极高 ✓
团队规模中小~中中~大
适合场景客户端/嵌入式/有版本合同Web / SaaS高频发布 + 成熟工程能力

决策树:

text
要同时维护多个已发布版本吗?
  ├─ 是 → Git Flow ✓
  └─ 否 → 发布频率是?
        ├─ 一天多次 → Trunk-Based(**前提:CI 够强 + 有 Feature Flag**)✓
        └─ 一周一次 / 随时 → GitHub Flow ✓(**默认推荐**)

⚠️ 不要"因为 Git Flow 听起来更专业"就选它 ✗

分支模型越复杂,协作成本越高。能用简单模型解决问题时,就别上复杂的 ✓

这与 《MySQL 性能优化基础》 的"归档优于分库分表"、《JSP 与 JSTL(技术演进理解)》 的"内部系统不上 SSR"是同一种判断 ✓

5.6 PR 与 Code Review ​

一次 PR 应该包含什么:

项说明
① 做什么(一句话)标题就要说清 ✓
② 为什么关联 issue(Closes #123)✓
③ 怎么验证的测了哪些场景 ✓
④ 风险与需要重点看的地方 ★"改了金额计算,请重点看对账逻辑" ✓
⑤ 截图 / 日志(UI 或行为改动)让 reviewer 不用自己跑 ✓

Reviewer 该看什么(按优先级):

优先级看什么
1正确性:逻辑对不对?边界情况处理了吗?
2安全性:有没有注入、越权、敏感信息泄漏?(《Filter、Listener 与会话管理》、《JSON 与 XML》)★
3可读性:半年后还能看懂吗?命名清楚吗?
4设计:有没有更好的做法?有没有重复?
5风格:缩进、命名规范(交给工具,别用人的时间争论)✓

第 5 条的关键:

格式、缩进、命名风格这些,应该用工具(Formatter / Checkstyle)自动处理 ✓

Code Review 的时间应该花在"工具看不出的问题"上 ——逻辑、安全、设计 ✓

在 Review 里争论"这里该不该换行"是巨大的浪费 ✗(见 《代码规范与自动校验》)

几条"Review 礼仪":

建议说明
区分"必须改"与"建议"用不同的前缀(如 [必须] / [建议])✓
说理由"这里可能为空"比"这样不好"有用 ✓
批准了就别拖小改动当天处理 ✓
有分歧时当面聊文字容易升级成争论 ⚠️

5.7 分支保护:让规则变成机制 ​

这是本节最"实用"的一节——因为它能真正防住事故。

必配的四条规则(GitHub / GitLab 都支持):

规则防什么
禁止直接 push 到 main ★防"跳过 review" ✗
禁止 force push ★防"改写已公开的历史" ✗(《Git 分支、合并与回退》 的 6.3)
必须 PR + N 人 approve防"一个人说了算" ✓
CI 必须全绿防"带病合入" ✓

可选但推荐:

规则说明
要求分支是最新的合并前必须同步主干(避免"合并后才发现问题")✓
禁止删除分支防止误删历史 ⚠️
签名提交某些合规场景需要

⚠️ 一个重要的提醒:

这些规则要在"仓库刚建好"的时候就配 ✓

等到出事再配,已经来不及了 ✗

还有一条"人"的规则值得考虑:保护规则要有人能临时绕过(如线上事故需要紧急合并)——但要留下痕迹(记录谁、什么时候、为什么)✓

5.8 版本号与分支 ​

语义化版本(SemVer):主版本.次版本.修订号

变更版本变化例子
不兼容的 API 变更主版本 +11.9.0 → 2.0.0 ✗(破坏了调用方)
向后兼容的新功能次版本 +11.9.0 → 1.10.0 ✓
向后兼容的 bug 修复修订号 +11.9.0 → 1.9.1 ✓

与提交类型的对应(《Git 分支、合并与回退》 的编程题):

text
feat:      → 次版本 +1
fix:       → 修订号 +1
feat!: 或 BREAKING CHANGE → 主版本 +1

打标签(标出"这个提交就是 1.2.0"):

bash
git tag -a v1.2.0 -m "1.2.0:支持手机号登录"
git push origin v1.2.0

本项目就在用这套方式 —— 每个阶段一批课程产出后打一个标签:

text
v0.1.0-skeleton → v1.0.0-s1(S1 全量交付)→ v2.0.0-ta(测试专项)→ v2.4.0-web-basics(Web 底层)

这样"某个阶段的成果"随时可以被检出、被对比 ✓

6. 递进示例 ​

6.1 最小示例:GitHub Flow 的一次改动 ​

bash
git checkout main && git pull
git checkout -b fix/login-error-message
# ... 改代码
git add . && git commit -m "fix: 登录失败时提示信息不明确"
git push -u origin fix/login-error-message
# 在平台上开 PR → review → 合并 → 部署

6.2 业务示例:一次 hotfix(最容易出错的流程) ​

bash
# ① 从 main 切
git checkout main && git pull
git checkout -b hotfix/payment-timeout

# ② 修 + 提 PR 合回 main(走 review)
git commit -m "fix: 支付回调超时导致订单状态未更新"
# PR → 合并到 main → 部署 ✓

# ③ ★ 千万别忘:同步回 develop
git checkout develop
git merge --no-ff hotfix/payment-timeout        # 或再开一个 PR
git push

第 ③ 步就是"下个版本不再出现同样 bug"的保证 ✓

更好的做法:让 CI 在 hotfix 合并后自动开一个"回合 develop"的 PR(《Git 分支、合并与回退》 综合任务的方案 ③)——人只需要确认 ✓

6.3 反例:长期存在的 feature 分支 ​

text
feature/new-checkout  存活了 3 个月 ✗

后果:

后果说明
合并冲突成灾主干已经前进了 3 个月 ✗✗
"合并地狱"一次合并几百个冲突
隐性知识这 3 个月的改动只有一个人知道 ⚠️
风险合并后可能引入没人预料到的问题 ✗

修复方式:

做法说明
拆小 ★把大功能拆成多个可独立发布的小改动 ✓
频繁同步每天把 develop/main 合进自己的分支(《Git 分支、合并与回退》 的 5.3)✓
用 Feature Flag ★★主干上开发、用开关关掉,避免长期分支 ✓

第三条是最彻底的解法:如果功能能"关掉",它就可以安全地待在主干上,不需要单独分支 ✓

7. 完整可运行命令 ​

本节没有单独的 labs 代码——本仓库自己就是例子。可以先看看它的现状:

powershell
cd <仓库根目录>
git branch -a                                  # 有哪些分支
git tag --list                                 # 有哪些标签
git log --oneline --decorate | Select-Object -First 10   # 最近的提交

预期输出(示意):

text
* main
  (本仓库目前只有 main 一个分支——单人开发时这是最常见也最合理的状态)

v0.1.0-skeleton
v1.0.0-s1
v2.0.0-ta
v2.1.0-data-access
v2.2.0-spring-boot-engineering
v2.3.0-mysql-performance
v2.4.0-web-basics

25e8016 (HEAD -> main, tag: v2.4.0-web-basics) feat: B3 Web 底层四节...
7ee0abc (tag: v2.3.0-mysql-performance) feat: B2 MySQL 优化两节...
60a7956 (tag: v2.2.0-spring-boot-engineering) feat: B1 Spring Boot 工程化三节...

三处观察:

观察说明
只有一个 main 分支单人项目不需要复杂分支模型 ✓(这正是 5.5 节"能用简单就别复杂"的例子)
每个阶段一个 tag里程碑可以随时被检出、被对比 ✓(5.8)
提交信息有规律feat: B1 xxx / feat: B2 xxx —— 批量产出时也能一眼看出结构 ✓

想在本地体验"多分支协作":按 《Git 分支、合并与回退》 第 7 节的办法,在系统临时目录里建一个演示仓库,然后:

powershell
# 建 develop 与两个 feature,模拟 Git Flow 的分支结构
$repo = "$env:TEMP\kb-git-demo"; cd $repo
git branch develop
git checkout -b feature/pay develop
"pay" | Set-Content -Encoding utf8 pay.txt; git add .; git commit -m "feat: 支付方式"
git checkout -b feature/refund develop
"refund" | Set-Content -Encoding utf8 refund.txt; git add .; git commit -m "feat: 退款"
git checkout develop
git merge --no-ff feature/pay -m "merge: 合入 feature/pay"
git merge --no-ff feature/refund -m "merge: 合入 feature/refund"
"===== 两个 feature 合入 develop 之后 ====="
git log --graph --oneline --all --decorate | Select-Object -First 10

预期输出(多分支并存的结构):

text
*   xxxxxxx (HEAD -> develop) merge: 合入 feature/refund
|\
| * yyyyyyy (feature/refund) feat: 退款
* | zzzzzzz merge: 合入 feature/pay
|\|
| * wwwwwww (feature/pay) feat: 支付方式
|/
* ...        (develop 与 main 的共同祖先)

注意 --no-ff 的作用:它会强制生成一个"合并提交",即使可以快进 ✓ ——这样历史里能看出"这里合入过一个功能"(Git Flow 推荐这么做)✓

8. Debug 观察点 ​

  1. 看分支保护是否生效:在一个配了保护的仓库里,试着直接 push 到 main——观察被拒绝的提示 ✓;
  2. 对比 --no-ff 与默认(快进)的合并:用 git log --graph 看两次结果的差别(快进时看不出"合并过")✓;
  3. 看 tag 指向哪里:git show v1.0.0 --stat —— 确认"这个版本包含了什么" ✓;
  4. 模拟"忘了合回 develop":建一个 hotfix,只合到 main,然后在 develop 上检查有没有那个修复 ✗ ——体会"为什么下个版本会复发" ✓;
  5. 观察长期分支的合并成本:建一个分支,在主干上改 10 次,再合并——数一数冲突 ⚠️。

9. 常见错误 ​

错误 1:为了"规范"选了过重的分支模型 ​

见 5.5 节。五人小团队做 Web 项目用 Git Flow,维护成本大于收益 ✗

判断:你们的发布节奏需要"版本分支"吗?不需要就别用 ✓

错误 2:hotfix 忘了合回开发分支 ​

见 5.2、6.2 节。这是 Git Flow 最常见的事故 ✗

解法:PR 模板加检查项 + CI 自动开回合同步的 PR ✓

错误 3:分支保护只配一半 ​

text
配了"必须 PR",但没配"禁止 force push" ✗

后果:有人仍能通过强推改写历史 ✗

建议:四条基本规则一起配(5.7)✓

错误 4:在 Review 里争论代码风格 ​

见 5.6 节。用工具解决风格,把人的时间留给逻辑与安全 ✓

错误 5:PR 太大 ​

text
一个 PR 改了 30 个文件、2000 行 ✗

后果:reviewer 看不完(或只看前几行就批准) ⚠️ ——Review 形同虚设 ✗

建议:PR 控制在"能在 20 分钟内看完"的规模(经验值:几百行以内)✓ 大改动拆成多个小 PR(每个都能独立合入)✓

错误 6:没有"谁可以合并"的规则 ​

建议:明确"谁负责合并"(通常是作者自己,在 approve 之后)——避免"以为对方会合" ✗

10. 动手实验 ​

目标:把"分支模型 + 回合 + 保护"这三件事亲手做一遍。

步骤:

  1. 按第 7 节的办法,在演示仓库里建 develop + 两个 feature,用 --no-ff 合并,观察多分支图;
  2. 模拟 hotfix 的完整流程:从 main 切 → 修 → 合回 main → 再合回 develop → 用 git log --graph --all 确认两个分支都有这个修复 ✓;
  3. 故意"忘了"合回 develop:重复第 2 步但不做最后一步 → 然后切到 develop 检查(应该没有那个修复)✗ ——这就是事故现场 ✓;
  4. 对比 --no-ff 与快进合并:同一个场景做两次(一次加 --no-ff),对比 git log --graph;
  5. 在 GitHub/GitLab 上建一个测试仓库,试着配一遍分支保护(禁止 push main、禁止强推、需要 1 人 approve),然后自己试着违反它,观察被拒绝 ✓;
  6. 用本仓库练"读历史":git log --oneline --decorate | Select-Object -First 20 —— 看看"每个阶段打一个 tag"的效果 ✓。

验收方式:能说出第 3 步"为什么下个版本会复发"、第 4 步两种合并的差别。

扩展任务:为一个"假想团队"写一份 CONTRIBUTING.md:

  • 包含:分支命名、提交信息格式、PR 模板、review 要求、合并规则;
  • 每一条都要写"为什么"(不写理由的规范很难被执行)✓;
  • 说明:这份文档该放在仓库哪里?怎么保证新同事会看到?(提示:CONTRIBUTING.md 在根目录,PR 时 GitHub 会自动提示)

11. 练习题 ​

基础题

  1. 判断:Git Flow 是最"标准"的分支模型,任何团队都应该用它。(对 / 错)
  2. 填空:Git Flow 的五类分支是 main、develop、、、______;其中 ______ 必须同时合回 main 与 develop。
  3. 简答:为什么"分支保护"要在平台层面配,而不是口头约定?

代码阅读题

text
仓库里有这些分支:
  main
  develop
  feature/order-list
  feature/payment
  release/2.1
  hotfix/login-error
  1. 这是一个什么分支模型?判断依据是什么?
  2. hotfix/login-error 修完之后应该合回哪些分支?如果只合回 main 会怎样?

编程题

  1. 为一个 6 人团队写一份分支与协作规范:
    • 场景:Web 项目,两周一个版本,偶尔需要紧急修复;
    • 要求:
      • 选一种分支模型并说明为什么(不要用"最标准"当理由);
      • 写出分支命名规则;
      • 写出从"接到需求"到"上线"的完整步骤(每一步谁做什么);
      • 设计分支保护规则(至少四条);
      • 设计PR 模板(含必填项);
    • 回答:为什么"偶尔需要紧急修复"这个条件,会影响你对模型的选择?

综合任务

  1. 排查并改进一个团队的协作流程:
    • 现状:团队用 Git Flow,但经常出问题—— ① feature 分支平均存活 3 周,合并时冲突很多; ② 每次发布前,"回合 develop"这一步总有人忘; ③ PR 平均要等 2 天才有第一个 review; ④ 有人为了"省事"直接 push 到 develop(没配保护);
    • 要求:
      • 针对每一条给出根因分析(不要只给"要记得"这种答案);
      • 给出可落地的改进措施(技术措施优先于流程规定);
      • 说明改进后如何验证有效(用哪些指标);
      • 说明"如果这些改进只能做一件,先做哪一件"并说明理由;
    • 额外要求:把 ④ 这种情况与 《Filter、Listener 与会话管理》 的"默认拒绝 + 白名单"对照,说明它们的共同原则。
分级提示

提示 1(方向):第 1 题的方向是"没有最好的,只有最合适的"。

提示 2(关键点):第 5 题——hotfix 从哪个分支切的?它修的是哪个环境的问题?

提示 3(接近答案):第 7 题的"验证指标"——想想"PR 从创建到合并的时间""合并时的冲突数量""发布后回滚次数"这类可度量的东西。

12. 参考答案 ​

基础题
  1. 错。没有"最标准"的分支模型,只有"最适合当前发布节奏"的 ✓

判断依据(5.1、5.5):

text
要同时维护多个版本吗?  ──是──→ Git Flow
        │否
        ↓
发布频率?──一天多次──→ Trunk-Based(需要强 CI + Feature Flag)
        │
        └──随时 / 两周──→ GitHub Flow(**默认推荐**)

"Git Flow 听起来很规范"是一种错觉 ✗ ——它的复杂度是有代价的,只在"需要版本分支"时才值得付 ✓

一个现实观察:很多声称"我们用 Git Flow"的团队,实际上只在用它的"main + feature"部分 ✓ ——develop 和 release 分支反而是负担 ⚠️

这说明:模型要跟着实际需要裁剪,而不是照搬 ✓

  1. feature/*、release/*、hotfix/*;hotfix/*。

为什么 hotfix 要合回两个分支:

分支为什么需要这个修复
main线上正在出问题——必须立刻修 ✓
develop下个版本也基于旧代码——不回合就会出现"修过又复发" ✗✗

这就是第 4 节"周三那件事"的机制 ✓

  1. 因为"口头约定"在压力下一定会被破坏 ✗

对比:

口头约定平台规则
忙起来时被跳过 ✗仍然生效 ✓
新人不知道照样违反 ✗自动生效 ✓
出错后"我以为可以"根本没有这个选项 ✓

一个具体的场景:

text
凌晨两点线上出事,你想"就这一次"直接推 main
  · 口头约定:你推了,第二天被发现,大家讨论要不要批评
  · 平台规则:push 被拒绝 → 你只能走 PR(但可以走"紧急 PR"流程,仍然留痕)✓

关键:平台规则不是"不信任人",而是"让人在紧急时也不会做错" ✓

好的工程实践是"让正确的做法成为最容易的做法" ✓

这与 《参数校验与全局异常处理》 的"统一异常处理"、《Git 分支、合并与回退》 的"--force-with-lease"、《JSP 与 JSTL(技术演进理解)》 的"默认转义"是同一条原则 ✓

代码阅读题(第 4、5 题)

第 4 题:这是 Git Flow ✓

判断依据(三条):

依据说明
有 developGit Flow 的标志(GitHub Flow 没有)✓
有 release/2.1发布准备分支——Git Flow 特有 ✓
有 hotfix/*Git Flow 特有(GitHub Flow 的紧急修复也是从 main 切的普通分支)✓

第 5 题:应该合回 main 和 develop ✓

如果只合回 main:

后果说明
下个版本(release/2.2 或 develop 上的内容)仍然有这个 bug ✗因为 develop 从来没收到这个修复
而且很难发现测试环境的 develop 分支上,"登录报错"这个问题"确实是存在的"——没人会以为"它应该已经被修了" ⚠️
直到 2.2 发布后才被发现 ✗✗这时又要再修一次,甚至可能又要一个 hotfix

这个"很难发现"是问题最麻烦的地方:

如果修了没生效,会立刻被发现;但"忘了同步到另一个分支",要等到下个版本发布才会暴露 ✗

这类"延迟暴露"的问题,正是需要流程/工具来兜住的原因 ✓

三种解法(《Git 分支、合并与回退》 综合任务的延伸):

方案强度成本
PR 模板加勾选项中 ⚠️低 ✓
CI 检查:hotfix 合并到 main 后,检查 develop 是否包含该提交,不包含就失败 ★强 ✓中
CI 自动开"回合 develop"的 PR ★★最强 ✓中

第三个最优:它把"记得做"变成了"确认一下" ✓

实现思路(伪代码):

bash
# CI 在 hotfix 合并到 main 后运行
if git merge-base --is-ancestor <hotfix-commit> origin/develop; then
    echo "✓ develop 已包含该修复"
else
    echo "✗ develop 缺少这个修复,自动创建回合 PR"
    gh pr create --base develop --head main --title "chore: 同步 hotfix 回 develop"
fi

git merge-base --is-ancestor 是一个很有用的检查:判断"某个提交是否已经在另一个分支上" ✓

编程题(第 6 题)

选择:GitHub Flow ✓(而不是 Git Flow)

理由(对应场景:"Web 项目、两周一个版本、偶尔紧急修复"):

条件对模型的要求GitHub Flow 是否满足
Web 项目不需要维护多个已安装的版本 ✓✅
两周一个版本不是"随时发"也不是"多版本并行" ⚠️✅(每周/两周发完全没问题)
偶尔紧急修复需要"从 main 快速切分支修完就上" ✓✅(从 main 切一个 fix 分支即可)
6 人中等规模,需要清晰的规则✅(规则简单反而更容易遵守)✓

为什么不用 Git Flow:

"两周一个版本"听起来像"需要 release 分支",但其实不需要 ✗

release 分支的价值在于"冻结功能、只修 bug"——但两周的迭代里,通常直接"从 main 切一个发布标签"就够了,不需要额外一条分支来维护 ⚠️

而且 Git Flow 的 feature → develop → release → main 三跳路径,在 6 人团队里会显著增加冲突与同步成本 ✗

⚠️ "偶尔需要紧急修复"为什么影响选择:

考虑说明
Git Flow 有专门的 hotfix 分支 ✓看起来"更适合"
但 GitHub Flow 也能做 ✓从 main 切一个 fix/xxx 分支 → PR → 合并 → 部署 ——路径更短 ✓
Git Flow 的 hotfix 必须合回 develop ⚠️这是一条"必须记得"的规则(《Git 分支、合并与回退》 事故 ②)
GitHub Flow 没有"开发分支" ★所以根本不存在"忘了同步"这个问题 ✓✓

这是本题最关键的一点:

GitHub Flow 因为"没有 develop 分支",从结构上消除了"hotfix 忘了回合"这类事故 ✓

少一个分支,就少一类需要"记得做"的事 ✓

这比"配一个提醒"更彻底 ✓


《分支与协作规范》

分支命名:

text
main                          主干(永远可发布)
feature/<简短描述>            新功能       例:feature/order-export
fix/<简短描述>                缺陷修复     例:fix/login-error-message
hotfix/<简短描述>             线上紧急修复  例:hotfix/payment-timeout
chore/<简短描述>              杂项(依赖升级、文档)例:chore/bump-spring-boot

规则:全小写、用短横线、不含中文与空格(避免 URL 与脚本处理出问题)✓

完整流程(从需求到上线):

步谁做什么
1开发从 main 切 feature/xxx(切之前先 git pull)✓
2开发开发 + 自测;提交信息用 Conventional Commits ✓
3开发提交前:git fetch + git rebase origin/main(同步主干,减少冲突)✓
4开发开 PR,填模板,关联 issue ✓
5CI自动跑测试 + 静态检查(必须全绿)✓
6Reviewer(≥1 人)看正确性、安全性、设计;批准 ✓
7开发合并(Squash and merge,保持 main 历史整洁)✓
8CI/CD合并后自动部署到测试环境 → 通过后发布生产 ✓
9值班线上出事 → 从 main 切 hotfix/xxx → 紧急 PR(1 人 approve 即可) → 合并 → 部署 ✓

分支保护规则(四条):

规则值
禁止直接 push 到 main✅ 开启
禁止 force push✅ 开启
必须 PR + 至少 1 人 approve✅(紧急修复可放宽为"值班同学 1 人")
CI 必须通过✅ 开启

推荐再加:"要求分支与 main 同步后才能合并" ✓(避免"合并后 CI 才发现问题")

PR 模板(.github/pull_request_template.md):

markdown
## 做了什么
(一句话说明)

## 为什么
(关联 issue:Closes #123)

## 怎么验证的
- [ ] 正常流程
- [ ] 边界情况(列出哪些)
- [ ] 错误情况

## 需要重点 review 的地方
(★ 例如:"改了金额计算,请重点看对账逻辑与取整")

## 风险与回滚方式
(有问题时怎么回滚:关开关 / 回退版本)

⚠️ "风险与回滚方式"这一项值得单独强调:

写 PR 时想一遍"如果上线后出问题怎么办" ——这会倒逼你在实现时就考虑可回滚性 ✓

比如:新逻辑用 Feature Flag 包起来(这样回滚 = 关开关,不用重新发版)✓

综合任务(第 7 题)

逐条根因分析

#现象根因(不是"要记得")
①feature 分支平均存活 3 周,冲突多不是"合并技巧不够",而是"分支存活太久" ✗ ——3 周内主干已经前进了很多(《Git 分支、合并与回退》 5.3 的"合并痛苦与存活时间超线性关系")
②回合 develop 总有人忘不是"记性不好",而是"这件事依赖人记得,且做错了不会立刻报错" ✗ ——延迟暴露的问题必须靠工具 ✓
③PR 平均等 2 天不是"大家不积极",而是"没有明确 review 的优先级" ⚠️ ——review 被排在"自己的开发"后面
④直接 push develop不是"不守规矩",而是"这件事根本没有被禁止" ✗ ——没有平台规则 = 默认允许

第 ④ 条最关键:

"没配保护"本身就是一种设计——它的意思是"允许任何人直接推"。

问题不在违规的人,在于规则不存在 ✓

改进措施(技术优先)

#措施类型
①缩短分支寿命:大功能拆小;每天同步主干(git rebase origin/develop)✓流程 + 习惯
①引入 Feature Flag:长期功能在主干上开发,用开关关掉 ✓技术 ★★
②CI 自动开"回合同步"的 PR ✓技术 ★★
②或 CI 检查 develop 是否包含该修复,不包含就失败 ✓技术 ★
③规定 review 的 SLA(如"PR 创建后 24 小时内必须有人看")+ 每天固定一个"review 时段" ✓流程
③PR 拆小(几百行以内)→ review 更快 ✓流程
④配分支保护:禁止直接 push、禁止强推、必须 PR ✓技术 ★★★

验证改进是否有效的指标:

指标怎么测目标
分支存活时间从分支创建到合并的天数(可用 CI 或脚本统计)从 3 周 → < 3 天 ✓
合并时的冲突数合并时冲突文件数(或"需要手工解决的冲突次数")显著下降 ✓
PR 首次 review 时间创建到第一个评论/approve从 2 天 → < 4 小时 ✓
PR 从创建到合并—下降 ✓
直接 push 到 develop 的次数平台审计日志0 ✓✓
发布后回滚次数每次发布记录下降 ✓
"修过又复发"的 bug 数issue 里标记为"重复出现"的0 ✓✓

怎么获取这些指标:平台的 API(GitHub/GitLab 都能查 PR 与合并数据)+ 一个简单的统计脚本 ✓

只做一件,先做哪件:④ 配分支保护 ✓

理由:

理由说明
成本最低在平台上勾几个复选框,10 分钟 ✓
效果最确定"禁止"是二元的——配了就 100% 生效 ✓
风险最高直接 push develop 可能绕过所有 review 与 CI ✗✗ ——这是"最危险的口子" ✓
不依赖他人配合其他三条都需要改变团队习惯(需要时间);这条不需要 ✓

对照 《Filter、Listener 与会话管理》 的"默认拒绝 + 白名单":

《Filter、Listener 与会话管理》 的鉴权本题的分支保护
默认拒绝(全拦)✓拒绝(禁止直接 push)✓
显式放行白名单(/login、/health)✓PR + approve(显式的审核动作)✓
漏配的后果多拦了 → 立刻发现 ✓多拦了 → 立刻发现 ✓
反过来的做法枚举"需要保护的路径" ✗ 迟早漏"允许直接 push,请大家自觉" ✗ 迟早出事
核心原则Deny by Default ✓Deny by Default ✓

共同原则:

"默认允许 + 希望大家守规矩"是不可靠的;"默认拒绝 + 显式放行"才是可依赖的。 ✓

这条原则贯穿本知识库的很多地方:

它们的共同点是:把"正确性"从"人的注意力"转移到"机制"上 ✓

因为人的注意力是稀缺且不可靠的资源,而机制不是。 ✓

13. 掌握标准 ​

  • [ ] 能说出"分支模型是对发布节奏的适配",不把某种模型当标准答案;
  • [ ] 能画出 Git Flow 的五类分支及其流转;
  • [ ] 知道 hotfix 必须合回 main 与 develop,并知道"忘了"的后果与解法;
  • [ ] 能说出 GitHub Flow 与 Trunk-Based 的适用场景;
  • [ ] 知道一次 PR 该包含什么、review 该看什么(风格交给工具);
  • [ ] 能列出四条基本的分支保护规则;
  • [ ] 知道语义化版本与提交类型的对应;
  • [ ] 理解"默认拒绝 + 显式放行"这一通用原则。

14. 扩展资源 ​

15. 下一步学习 ​

《Maven 进阶:依赖管理与多模块》:把"构建与依赖"这一层管起来。

后续知识

暂无

进度只保存在本机浏览器,可随时清除

个人学习项目:AI 生成内容均经人工复核,第三方资源仅作索引