真正有效的分支保护必须在远端平台配置,本地hook仅提示无效;github需在settings→branches→add rule中设置main规则,并勾选include administrators、审批数、状态检查及禁用force push;gitlab需分别配置allowed to merge和allowed to push权限,移除developer的push权限并启用code owner审批。

Git 本身不提供分支保护功能,所有真正有效的分支保护规则都必须在远端代码托管平台(GitHub / GitLab / Azure DevOps)上配置。本地 git 命令或 .git/hooks 无法阻止 push —— 它们最多只能提醒,删掉 hook 就失效。
GitHub 上怎么给 main 分支加保护?
进仓库 Settings → Branches → Branch protection rules → Add rule,填 main(或 master)后保存。但默认勾选的选项远远不够:
- 必须勾选
Include administrators,否则你作为 Admin 能直接 push 破坏规则 -
Require pull request reviews before merging要配合Dismiss stale pull request approvals when new commits are pushed,否则旧审批可能被复用 - 如果用了 GitHub Actions,务必勾选
Require status checks to pass before merging并手动选中关键 job 名(如test、build),否则 CI 失败也能合入 -
Allow force pushes默认关闭,但若曾手动开启过,得再关一次;Require code owners review需先提交CODEOWNERS文件才生效
GitLab 的 protected branches 怎么配才不漏?
GitLab 的权限是双维度的:Allowed to merge 和 Allowed to push 完全独立,且默认只保护 master,其他分支要手动添加:
- 别只改 “Developers + Maintainers” —— 必须把
Developer从Allowed to push列里移除,否则他们仍能直推 - 启用 CI/CD 后,一定要勾选
Require approval from code owners(前提是你已配置了.gitlab/CODEOWNERS) - GitLab 15.0+ 默认禁用 force push,但自建实例或老版本可能开着,需人工确认并关闭
- 保护规则对
protected branches页面里列出的每个分支单独生效,不能批量设置通配符(如release/*需逐个加)
CI 中如何补漏防止直推 main?
远端保护是第一道防线,CI 是第二道。可以在流水线开头加分支校验逻辑:
- GitHub Actions:
if: ${{ github.event_name != 'pull_request' && github.head_ref == 'main' }}不够可靠,应改用git rev-parse --abbrev-ref HEAD实际读取当前分支名 - GitLab CI:
script: | if [[ $(git rev-parse --abbrev-ref HEAD) == "main" ]] && [[ "$CI_PIPELINE_SOURCE" != "merge_request_event" ]]; then exit 1; fi - Azure DevOps:
- ${{ eq(variables['Build.SourceBranch'], 'refs/heads/main') && ne(variables['Build.Reason'], 'PullRequest') }}条件下直接 fail - 注意:这种检查只在 CI 运行时触发,无法拦截本地
git push,仅作兜底
真正的分支保护永远不在 .git/config 或 pre-push hook 里,而是在远端服务的开关上。哪怕你写了最严密的本地脚本,只要没在 GitHub/GitLab/Azure DevOps 的 UI 或 API 里打开对应分支的保护规则,就等于没设防。











