强制推送被拒是因分支保护规则生效,非权限或命令问题;GitHub/GitLab 的远端规则才是唯一可靠防线,本地 hook 无效,且规则需按分支单独配置。

GitHub上强制推送被拒,是因为分支保护规则生效了
不是权限不够,也不是命令写错,而是远端平台明确拦截了 git push --force 和 git push --force-with-lease。只要分支启用了 prevent force pushes,所有重写历史的操作都会被拒绝,哪怕你是仓库 Owner 或 Admin —— GitHub 的设计就是“规则高于权限”。
常见错误现象:! [remote rejected] main -> main (refusing to allow a force push)。这不是网络或认证问题,也不用换 token 或重配 SSH,直接去 Settings → Branches → Branch protection rules 查这条规则是否已启用。
- 必须勾选
Include administrators,否则管理员能绕过所有规则 -
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 失败也能合入
GitLab里force push被拒,要检查Protected branches的双维度权限
GitLab 的保护逻辑和 GitHub 不同:它把 Allowed to merge 和 Allowed to push 拆成两个独立开关。即使你设了 protected branch,如果 Developer 还在 Allowed to push 列表里,他们依然能直接 git push 或 git push -f。
真正有效的配置是:
- 进 Settings → Repository → Protected branches,找到目标分支(如
main) - 把
Developer从Allowed to push中移除(只留Maintainer或Owner) - 确认
Allow force push是关闭状态(GitLab 15.0+ 默认关,但自建实例或老版本可能开着) - 若启用了 CI/CD,务必勾选
Require approval from code owners,且确保仓库根目录存在.gitlab/CODEOWNERS
本地 pre-push hook 不能替代远端保护
有人试图用 .git/hooks/pre-push 拦截 --force,这完全无效。hook 只运行在本地,删掉文件或跳过 hook(git push --no-verify)就能绕过。真正的防线只在远端 —— GitHub/GitLab/Azure DevOps 的分支保护规则才是唯一可靠手段。
典型误操作:
- 以为自己写了 hook 就安全了,结果别人 clone 后没这个 hook,照样能强推
- 在 GitHub 上只开了 PR review,但没勾
prevent force pushes,导致有人直接git push -f origin main - GitLab 里只改了
Allowed to merge,忘了清空Allowed to push,Developer 仍可直推
想临时允许 Owner 强推?别关保护,改权限粒度
紧急修复场景下(比如误删关键提交),不建议直接 Unprotect 分支 —— 这会瞬间放开所有限制。更稳妥的做法是保留保护,只调整权限:
- GitHub:在 Branch protection rule 里保持
prevent force pushes勾选,但确保Include administrators未勾选(注意:这是唯一能让 Admin 绕过的选项,慎用) - GitLab:编辑 Protected branches 设置,勾选
Allow owner to force push(不是Allow force push),这样只有 Owner 能强推,其他人仍被拦 - 操作完立刻恢复原设置,避免留下窗口期
最易被忽略的一点:分支保护规则对每个分支单独生效,release/* 这类通配符需逐个添加,不能靠正则或批量开关——漏配一个,就等于留了一道后门。


















