CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
GitHub Actions CI/CD/课时/PR 检查与分支保护
RawBlame
课时目录12 节

GitHub Actions CI/CD

  1. 01CI/CD 与 GitHub Actions
  2. 02Workflow 文件结构
  3. 03Jobs 与运行器
  4. 04Steps 与 Actions
  5. 05Secrets 与环境
  6. 06依赖缓存
  7. 07构建 Spring Boot
  8. 08构建 Next.js platform
  9. 09构建推送镜像
  10. 10部署策略
  11. 11PR 检查与分支保护
  12. 12综合练习

PR 检查与分支保护

pull_request 触发、required checks、fork PR 安全。

25 分钟

PR 检查与分支保护

这一课你将能做到

  1. 配置 on.pull_request(含 paths 过滤),让改动 backend/** / platform/** 时跑到对应检查
  2. 在仓库 Branch protection / Rulesets 里勾选 required status checks,使红测无法合并进 main
  3. 说明 fork PR 默认拿不到 write secrets 的原因,以及对 pull_request_target 的谨慎态度

为什么要学

CI 写得再漂亮,若大家还能「红着合并」,门禁等于海报。GitHub 把 workflow 的 job 结果变成 PR 上的 status check;再配合分支保护,main 才成为可信基线。

monorepo 还要省分钟数:只改文档时狂跑 Maven/npm 是浪费,paths 过滤是常用刀。但 paths 也会带来新坑——required check 没跑出来,PR 永远不能合。

本课把「何时跑」与「跑红能不能合」钉在一起,为综合练习收尾。

先建立图像

开发者开 PR → main
        │
        ▼
  pull_request 事件触发 ci.yml
        │
        ├─ job backend   → 成功/失败
        └─ job platform  → 成功/失败
                │
                ▼
  PR 页显示 checks
                │
  Branch protection: require backend + platform
                │
        全绿才可 merge(可再加 review 规则)

人话:workflow 是考卷;分支保护是「不及格不准毕业」的校规。没有校规,考卷只是建议。

机制作用
on: pull_request何时跑检查
job 结论产生 check 名称
Branch protection哪些 check 必须绿才能合
paths哪些文件变化才跑

跟着做

步骤 1:确认 PR 触发与 paths

name: CI

on:
  pull_request:
    branches: [main]
    paths:
      - 'backend/**'
      - 'platform/**'
      - '.github/workflows/**'
  push:
    branches: [main]
    paths:
      - 'backend/**'
      - 'platform/**'
      - '.github/workflows/**'

permissions:
  contents: read

jobs:
  backend:
    runs-on: ubuntu-latest
    # … 第 7 课的 setup-java + verify …
  platform:
    runs-on: ubuntu-latest
    # … 第 8 课的 npm ci / lint / test / build …

注意:仅改 README.md 时,带 paths 的 workflow 整份不跑——这是预期。若希望文档 PR 也有一条可勾的检查,需另设计小 job(进阶,见卡点急救)。

步骤 2:开一条真实 PR 看 checks

从 feature 分支改一行 backend 注释 → 开 PR。PR 页 Checks 应出现 job;点进日志确认触发事件是 pull_request。

步骤 3:配置分支保护

仓库 Settings → Branches(新版界面在 Rules → Rulesets):

  • 目标分支:main
  • 勾选 Require a pull request before merging(建议)
  • 勾选 Require status checks to pass:选 backend、platform(名称须与 job 名一致)

再用一个故意失败的 PR 验证:Merge 按钮应被挡住。这一步才是「门禁有牙齿」的证明。

步骤 4:核对 check 名称

若 job 写了:

  backend:
    name: Backend Verify

则保护规则里出现的是 Backend Verify 而不是 backend。实操顺序:先让 workflow 在 main 上跑成功一次,再在保护规则的下拉列表里选真实出现的名字。凭记忆手敲名称常出 Expected 悬挂。

步骤 5:理解 fork 与 secrets

来自 fork 的 PR:workflow 以只读 token 运行,拿不到 repository secrets(防恶意 workflow 偷钥)。因此「PR 里直接部署生产」在开源协作中通常不可行——这是安全特性不是缺陷。看到 fork PR 里部署步骤跳过/失败时,先对照该安全模型,而不是急着换事件类型。

步骤 6:记录 pull_request_target 警告

pull_request_target 在基础仓库上下文运行,能读 secrets,常用于「给贡献者自动评论」这类场景。但它与 checkout PR 分支代码组合执行时,曾多次造成真实安全事件。本课规则:默认不用;确需使用,先读完官方安全指南,严禁 checkout 并执行 PR 分支里的不可信脚本,权限收到最小。

讲清楚要点

  1. 因为合并后修复成本更高,所以检查应挂在 pull_request 上——把失败留在分支里。
  2. 因为没有保护规则时红测也能合,所以必须配 Branch protection / Rulesets——门禁要有牙齿。
  3. 因为 check 名来自 job,所以 YAML 里的 job name 与保护规则勾选项必须对得上——改名后要同步更新规则。
  4. 因为 monorepo 改动面不同,所以用 paths 节省分钟数——但要接受「只改文档可能无 CI」的后果或另补小 job。
  5. 因为 fork PR 不可信,所以默认不给 secrets——这是开源安全模型的一部分。
  6. 因为 workflow 文件本身也是被改对象,所以把 .github/workflows/** 纳进 paths——改 CI 的 PR 仍会被验证。

你可能会懵的地方

  1. 「为什么我的 PR 没有任何检查?」 查四点:workflow 是否已存在于默认分支;paths 是否把本次改动全过滤掉了;PR 目标分支是否匹配 branches: [main];仓库 Actions 是否被禁用。

  2. 「push 到 feature 分支与 PR 检查跑两次?」 开着 PR 时主要是 pull_request 在跑;若 workflow 还监听了 push 且不限分支,两个事件都会触发。用 branches 过滤 push 到 main、靠 pull_request 管分支检查,可去重。

  3. 「required check 一直显示 Expected?」 保护规则引用了一个从未跑出的名字(手敲错、或改名后旧名残留)。让 workflow 真跑一次,从下拉列表重选。

  4. 「管理员为什么还能合并红 PR?」 保护规则常含「允许管理员绕过」选项,或管理员点了 admin merge。要硬门禁就关掉绕过;团队约定上,红测合并必须留痕说明。

  5. 「paths 该怎么配才不会卡住 required checks?」 原则:required check 引用的 job 必须在任何目标分支的 PR 上都有机会跑。要么 paths 放宽到覆盖所有可能改动,要么对文档类 PR 跑一个轻量占位 job 保证 check 出现并变绿。

错法对照

错法问题正解
有 CI 无分支保护红也能合,门禁形同虚设require status checks
check 名与 job 名不一致却硬勾一直 Expected 卡合并跑通后从列表选真实名
paths 太窄(漏了 workflows/**)改 CI 无验证;或 required check 不跑把 .github/workflows/** 纳入 paths
为省事对 fork 开 pull_request_target 跑不可信脚本密钥与供应链风险默认 pull_request;例外先读安全文档

卡点急救

  1. required check 一直等不出现(PR 卡死不能合):本次 PR 的改动没命中 paths,workflow 没跑、check 不存在。处理:① 给 workflow 补上命中的路径;② 或临时用 admin 权限合入并修正 paths;③ 长期方案是给文档类改动配置一个轻量 docs 检查 job。
  2. PR 红了但仍能点合并:分支保护没生效——确认规则真的勾了 required status checks、目标分支写的是 main、且当前账号不是绕过角色;规则保存后开一条新 PR 验证。
  3. fork PR 的 job 失败提示缺 secret:这是预期安全模型。本仓库协作者可由维护者把分支拉进本仓库重跑(有 secrets);不可信内容绝不能用 pull_request_target 绕过。

面试常问

  • 如何为一个 monorepo 设计 PR 门禁? 分四层答:① 触发层——pull_request 指向 main,paths 按模块过滤,workflow 自身目录纳入 paths;② 检查层——各模块独立 job(backend verify、platform 四件套),便宜的检查靠前;③ 强制层——分支保护勾 required checks,禁止绕过,配合至少一人 review;④ 成本层——concurrency 取消过时 run,PR 内只跑快速检查、全量留给 main。核心权衡是「严格性 vs 分钟数」,并把策略写进仓库文档。

  • pull_request 和 pull_request_target 有什么区别?为什么后者危险? pull_request 在 PR 合并后的代码上下文运行,fork PR 只有只读 token、无 secrets,安全;pull_request_target 在基础仓库上下文运行,带 secrets 与写 token,本意是服务贡献者(自动打标签/评论)。危险在于:如果 checkout 了 PR 分支的代码并执行其中脚本,等于让外部代码拿着仓库密钥运行——历史上有多次真实供应链事故。原则:不可信代码与高权限上下文必须隔离。

  • 分支保护里 required checks 显示 Expected 卡住合并,怎么排查? 三步:① 对比规则里的 check 名与实际 run 里的 check 名(job 改名后旧名残留最常见);② 确认该 workflow 在本次 PR 上真的运行(paths、分支过滤、workflow 是否在默认分支);③ 若该检查由条件跳过(if: 为 false 时显示 skipped),required check 会等待——用 if: always() 或调整条件让 job 明确成功/失败而不是 skip。

自测三问

  1. 分支保护里勾选的 status check 名称通常来自哪里?改名后要注意什么?
  2. 为什么 fork PR 读不到部署密钥反而是件好事?
  3. 给 monorepo 的 paths 列出三个应包含的模式,并解释为什么包含 .github/workflows/**。

小结一句话

PR 触发检查,分支保护强制全绿;paths 控成本,fork 默认无密钥是安全特性。

延伸

  • About status checks
  • Managing branch protection rules
  • 下一课:综合练习——把 12 节课的零件装回本站仓库,拼出完整流水线。
加载本节练习…
← 上一课部署策略下一课 →综合练习