用 Rulesets 保护 GitHub 的 main 分支

摘要

规则拦的是推送

有写权限的人可以直接 git push origin main,Pull Request 和 Actions 都不会跑。git push --force 还会改掉 main 上已经存在的提交,别人基于旧历史做出的分支会对不上。规则写在 GitHub 上,由服务器拒绝这两种推送。功能分支不受影响,仍可 git push -u origin feature/xxx。

本文只写单个仓库的分支规则。组织里一批仓库共用的规则要 GitHub Team 或 GitHub Enterprise。按文件路径、大小拦截推送的是 push ruleset,只对私有或 internal 仓库生效,这里不写。

创建

打开仓库的 Settings。左侧在 Code, planning, and automation 下进入 Rulesets,再点一次 Rulesets。然后 New ruleset → New branch ruleset。

  • Ruleset name:例如 protect-main。

  • Enforcement status:选 Active。停在 Disabled 时,推送不会被拦。选 Evaluate 时推送仍然成功,页面上可以查看这次会违反哪些规则,用来先试再开。

  • Target branches:Add target → Include default branch。仓库的默认分支是 main 时,这条就作用在 main 上。

  • Bypass list 先留空。把 Repository admin 加成 Always allow 之后,管理员的 git push origin main 仍然成功,看起来像规则没生效。

  • Branch rules 勾选下面三项。Restrict deletions 和 Block force pushes 页面上经常已经勾着,确认它们是开的。

规则 作用
Restrict deletions 不能删除 main
Block force pushes git push --force 到 main 会被拒绝
Require a pull request before merging 变更要先有一个 Pull Request。这里不要求必须有人批准

勾了 Require a pull request before merging 之后,还可以填批准人数。填 1 时,至少一名有写权限的人批准后才能合并。自己一个人的仓库会因此合并不了自己的 PR,个人仓库可以保持不填,只留下「必须走 PR」这条记录。

点 Create。状态是 Active 时立即生效。

加上 Actions 检查

在同一条规则里勾 Require status checks to pass before merging。输入框里填检查的名字,再点添加。只打字、不添加,保存后这条检查不存在。

名字必须和 Pull Request 的 Checks 列表里那一项一致,例如 workflow 里 jobs 下的键是 build 时,这里通常就填 build。多一个空格会配不上,合并按钮会一直等一个不会出现的检查。

Require branches to be up to date before merging 打开时,功能分支要先接上最新的 main,检查才会被认作通过。这项在启用状态检查后默认是开的。检查名字还没添加时,这一项不会单独生效。

要求每个提交都已签名时,再勾 Require signed commits。签名方法见 用 SSH 密钥签名 Git 提交。分支上若已有未签名的提交,需要改写那些提交再推;Block force pushes 同时开着时,没有 Bypass 权限就推不上去。个人仓库先不要两样一起开。

确认已经生效

规则保存后,向 main 推一次。服务器拒绝时,输出里有 Repository rule violations,并写明违反的规则,例如必须通过 Pull Request。

1
git push origin main

这条失败,只说明 main 被拦住了。功能分支应仍能推上:

1
git push -u origin feature/xxx

功能分支也失败时,看 Target branches 是不是写成了全部分支。管理员推 main 却成功时,打开这条规则的 Bypass list。

停用或删除

还在 Rulesets 列表里点开 protect-main。把 Enforcement status 改成 Disabled 后保存,规则留着但不再拦截。不需要这条规则时,在页面上 Delete。删的是 GitHub 上的规则,本机仓库不用改。