--force是危险的无条件覆盖,极易炸掉他人提交;--force-with-lease是带远程SHA校验的安全强制推送,仅当本地缓存与远程状态一致时才允许推送,但依赖及时git fetch且受分支保护策略限制。

直接说结论:--force 就是定时炸弹,别用;--force-with-lease 也不是万能保险,但它是目前最靠谱的“刹车片”——前提是你会踩、且知道它什么时候会失灵。
为什么 git push --force 会炸掉同事的提交
它不看远程有没有新提交,只管把本地分支头(HEAD)硬塞过去。只要远程分支指针被你本地覆盖,所有没被你拉下来的提交就从远程历史里“蒸发”了——Git 不会警告,不会备份,也不会通知别人。
常见炸雷场景:
- 你刚
git rebase -i整理完本地提交,顺手git push --force origin main,而同事两小时前刚push了一个 hotfix - CI/CD 脚本里写了
--force,某次构建失败后重试,直接抹掉中间一次人工修复 - VSCode 插件点了个“Force Push”,背后调的是
-f而非--force-with-lease
git push --force-with-lease 怎么检查、又在哪会失效
它依赖本地缓存的远程引用(比如 origin/main 的 SHA),和远程当前 SHA 做比对。一致才推,不一致就报错:! [rejected] main -> main (stale info)。
但它不是“实时联网查”,所以这些情况会让它失效:
- 你很久没
git fetch origin,本地缓存过期 → lease 检查退化成--force - 远程分支被其他人用
--force或--force-with-lease推过多次,而你只 fetch 过一次 → 缓存只记得第一次的状态 - GitHub/GitLab 开启了分支保护(protected branches),默认拦截所有 force 类操作,此时
--force-with-lease也会被拒,错误信息可能是refusing to allow a GitHub App to create or update workflow files或类似权限提示
强制推送前必须做的三件事(缺一不可)
跳过任何一步,安全机制就形同虚设:
- 运行
git status确认工作区干净;否则git reset --hard origin/main可能丢掉未提交代码 - 运行
git fetch origin同步最新远程状态,再用git log --oneline origin/main..main看你本地到底新增了哪些提交 - 运行
git log --oneline main..origin/main查看远程是否有你没拉下来的提交;如果有,先决定是git merge、git rebase origin/main,还是找同事协调
被拒绝后别急着换 --force,先看清楚错在哪
收到 ! [rejected] main -> main (non-fast-forward),不代表“必须强推”。这只是一个信号:远程有你本地没有的提交。
这时候该做的是:
- 如果那些提交是你不需要的(比如测试分支误推到 main),确认无误后,再执行
git push --force-with-lease origin main - 如果那些提交是同事的正式修改,那就得停下来:要么
git pull --rebase整合,要么建新分支、提 PR,而不是强推覆盖 - 如果只是想“清空”远程分支(比如废弃旧实验分支),用
git push origin :branch-name删除更安全,无需 force
真正的坑不在命令本身,而在“以为自己知道远程状态”的那一刻——fetch 和 log 多敲两下,远比事后翻 reflog 恢复快得多。


















