gitlab protected branches 的安全性取决于 allowed to push 和 allowed to merge 的组合配置,而非单纯开启保护;developer 可创建 mr 但不能直接 push,因默认 push 权限仅限 maintainer 及以上,而 merge 权限开放给 developer 及以上。

GitLab 的 Protected Branches 不是“开了就安全”,而是“配错就形同虚设”。真正起作用的不是保护状态本身,而是两个独立开关:Allowed to push 和 Allowed to merge 的组合逻辑。多数权限事故,都源于混淆这两者或忽略角色继承关系。
为什么 Developer 推送失败却能创建 Merge Request?
这是最常被误解的起点。GitLab 默认把 master(或 main)设为受保护分支,但它的默认配置是:Allowed to push 仅限 Maintainer 及以上,Allowed to merge 却开放给 Developer 及以上。这意味着:
- Developer 可以向
master提交Merge Request(因为有merge权限),但不能直接git push origin master(因为没push权限) - 报错信息通常是:
remote: GitLab: You are not allowed to push code to protected branches. - 这个错误和你本地 Git 配置、SSH 密钥、甚至分支是否存在都无关,纯粹是服务端权限拦截
如何让 Developer 能 push 但不能 merge?
这在灰度发布、紧急 hotfix 或 CI 自动推送等场景下很实用。关键不是降级角色,而是精细化控制分支规则:
- 进入项目 →
Settings→Repository→Protected branches - 找到目标分支(如
develop),点击Edit - 将
Allowed to push设为Developers + Maintainers - 将
Allowed to merge设为Maintainers only - 务必关闭
Allow force push—— 否则git push -f会绕过所有审查
注意:该设置只对新规则生效。已存在的 MR 不受影响,但后续新建的 MR 若由 Developer 发起,将无法在 Web 界面点击 Merge 按钮。
哪些配置看似合理实则危险?
很多团队为了“方便开发”悄悄打开高危选项,结果埋下审计隐患:
-
Allowed to push = Developers + Maintainers+Allow force push = Enabled:等于完全放弃历史完整性,CI 失败后可直接覆盖主干 - 用通配符规则(如
release/*)但未勾选Include administrators:GitLab 管理员默认绕过所有保护,可能无意中跳过审批流程 - 多个重叠规则共存(如同时存在
main和main*):GitLab 按匹配顺序应用第一条,容易误判实际生效规则 - 依赖群组(Group)级保护,却在项目(Project)级修改了角色:群组设置会被项目设置覆盖,但开发者往往不知道层级优先级
强制推送(force push)到底能不能开?
答案几乎是“不能”,除非你明确接受以下后果:
- CI 流水线记录与实际代码历史脱节:
git log显示的提交可能从未通过测试 - 其他协作者的本地分支变成“孤儿”:他们
git pull后会看到大量冲突或diverged提示 - GitLab 的 MR 关联丢失:原 MR 页面显示 “This merge request was closed without merging”,但代码已上线
- 合规审计失败:SOC2、ISO27001 等标准明确要求禁止无痕覆盖关键分支历史
真要回滚,优先走 git revert + 正常 MR 流程;实在要 push -f,必须临时解除保护、操作后立即恢复,并留下审计日志。











