2024年,GitHub上每天有超过3000万次代码合并。其中相当一部分,正在经历一种荒诞的等待——改个文档错别字,却要排队等后端构建、集成测试、安全扫描全部跑完。
这些检查明明和文档毫无关系。但开发者只能干瞪眼。
问题的根源很隐蔽:GitHub的强制检查(Required Checks)是静态的,而拉取请求(Pull Request,代码合并前的审查单元)是动态的。这个错配让无数团队陷入两难——要么浪费计算资源,要么降低代码保护标准。
静态规则撞上动态现实
GitHub的分支保护机制设计于一个简单假设:所有进入主分支的代码,都应该经过同一套检查。这个假设在十年前成立,当时大多数仓库结构单一,前后端代码混在一起。
现代代码库早已不同。一个典型项目可能包含:前端界面、后端API、数据库迁移脚本、文档站点、CI配置。改文档的人不该为数据库Schema变更买单,改CSS的人不需要跑机器学习模型测试。
但GitHub的强制检查列表是写死的。管理员在设置页面勾选"需要状态检查通过",然后指定一组工作流名称。这组名称对所有PR生效,无论实际改了什么文件。
团队被迫在三个坏选项里挑一个:
选项一:全量要求。所有检查对所有PR强制生效。结果是改个README要等45分钟,CPU时间白白烧掉。
选项二:降级保护。取消某些检查的强制要求,换取速度。风险是危险代码可能趁虚而入。
选项三:假装条件执行。这是最常见的折中。保持工作流在强制列表里,但用路径过滤(path filters)或文件变更检测,让不相关的任务快速退出。
代码看起来像这样:
```yaml
on:
pull_request:
paths:
- "api/**"
- "db/**"
- "auth/**"
表面聪明,实则埋雷。
执行逻辑偷走了政策决策
路径过滤解决的是"这个工作流该不该运行"。但它回答不了另一个问题:"这个PR需不需要这项检查才能合并"。
这是两个完全不同的层面。前者是执行效率,后者是合并政策。GitHub把它们捆在了一起。
举个例子:一个只改docs/的PR,路径过滤让后端工作流跳过,状态显示为"跳过"或成功。分支保护看到绿色对勾,放行合并。看起来没问题?
再换一个场景:PR同时改了api/和docs/。后端工作流正常运行,但文档检查被路径过滤跳过了。如果文档检查也在强制列表里,这个PR永远合并不进去——因为工作流根本没运行,没有状态可以上报。
团队被迫在CI配置里写越来越多的壳逻辑。检测文件变更、条件设置输出、动态决定报告什么状态。YAML文件膨胀成几百行,里面藏着合并政策的暗线。
「这相当于把交通规则写进了汽车发动机的控制程序」,一位在Stripe基础设施团队工作过的工程师这样比喻,「车能跑,但换个车型就得重写规则。」
更隐蔽的代价是认知负担。新加入的开发者看到绿色的CI通过,以为所有检查都跑了。实际上可能只是壳逻辑判断"这次不用跑"。调试失败时,需要同时理解GitHub的分支保护、工作流的触发条件、以及藏在shell脚本里的决策树。
分离执行与政策:一个更干净的模型
理想状态应该很直观:同一个保护分支,不同PR可以有不同的强制检查清单。
改文档的PR:文档lint、拼写检查、快速审批路径。
改核心API的PR:单元测试、集成测试、安全扫描、两名资深审查者批准。
两者互不影响。系统根据PR实际内容,动态计算需要满足的条件。
这需要把"什么检查要跑"和"什么检查必须通过"拆开。前者是执行层,后者是政策层。GitHub目前只提供了前者。
一些团队开始自建解决方案。GitHub Apps监听pull_request事件,分析变更文件,然后动态推送一个聚合状态——比如叫"MergeGuard"——到分支保护。真正的检查分散在各个工作流,由App决定哪些结果对这个PR算数。
这个模型有个诱人之处:它把政策逻辑集中到一个地方。不再需要在十几个YAML文件里同步路径过滤规则。变更范围分析、检查要求映射、例外情况处理,都在App里完成。
但自建也有代价。维护一个高可用的GitHub App、处理Webhook投递失败、应对API速率限制、保证状态计算的确定性。小团队往往望而却步。
市场上也出现了商业产品填补这个空白。2023年成立的Mergify、更早的Trunk.io,都提供了基于变更内容的动态合并条件。它们的核心卖点不是功能更多,而是"让GitHub原生应该支持的东西变得可用"。
为什么GitHub迟迟不动
这不是技术难题。计算PR的变更范围、匹配规则、动态调整强制检查列表,工程实现并不复杂。
更可能的障碍是产品哲学。GitHub的分支保护设计强调简单和可预测:管理员看一眼设置页面,就能知道什么能进主分支。动态规则引入了不确定性——同一个分支,不同PR的门槛不同,审计追踪也更复杂。
但现状的"简单"是假象。它把复杂性推给了用户,让用户用壳逻辑和YAML技巧模拟本该原生支持的功能。
GitHub在2023年推出了"规则集"(Rulesets)功能,部分回应了这个需求。规则集允许更细粒度的分支保护,可以按分支模式、用户身份、甚至提交消息设置不同规则。但PR内容感知仍然缺失。
一个值得注意的对比是GitLab。它的合并请求批准规则支持基于代码变更路径的条件,原生区分"执行"和"要求"。GitHub的企业客户里,不乏因为这个差异而迁移或考虑迁移的团队。
竞争压力可能最终推动改变。但在那之前,3000万开发者还在继续写那些"假装条件执行"的YAML文件。
你的团队是怎么处理这个问题的——全量硬等、降级冒险,还是已经自建了动态规则系统?
热门跟贴