跳到主要内容

Git 安全强推:--force-with-lease

改写历史(rebase、squash、reset)之后必须强推,但 git push -f 是把双刃剑:它会把远程分支直接覆盖成你本地的样子,别人在这期间推上去的提交,在你不知情的情况下被抹掉。

--force-with-lease 只比 -f 多一个检查,代价极小,收益很大。

一、它检查什么​

git push --force-with-lease origin feature-x

被比较的是你本地的 origin/feature-x 引用(远程跟踪分支)和远程当前实际值:

  • 两者一致 → 说明没有人动过,允许覆盖
  • 两者不一致 → 说明远程有新提交,拒绝推送

一句话:"我以为远程就停在我上次看到的位置,如果不对,别动"。

二、为什么不直接 -f​

git fetch # 假设这时远端有人在推
git push -f origin feature-x # 直接覆盖,同事的提交没了

换成 --force-with-lease 就会报错:

! [rejected] feature-x -> feature-x (stale info)

这时先 git fetch 看一眼发生了什么,再决定要不要强制覆盖。

三、更严格的写法​

# 显式指定期望的远程 SHA,最严格
git push --force-with-lease=feature-x:9c8d7e6 origin feature-x

适合脚本化场景:明确知道自己要覆盖到哪个版本。

四、常见坑​

后台自动 fetch 会让 lease 失效:IDE 或某些工具会定时 git fetch,远程跟踪分支被刷新后,lease 检查就失去意义了(因为本地的"我以为"被更新了)。

结论:--force-with-lease 是防呆,不是安全保障。在共享分支上强推之前,永远先 git fetch 手动确认。

--force-with-lease 也有失败的可能:你会看到 stale info 或 rejected (non-fast-forward),别急着加 -f,先搞清楚远程多出来的提交是什么。

五、设成默认习惯​

git config --global alias.pushf "push --force-with-lease"

或者设成新版本的默认行为:

git config --global push.useForceIfIncludes false # 保持默认即可

六、该不该强推的判断​

分支强推
自己的功能分支、PR 还没被 review可以
PR 已经被 review,只是追加修改可以,但要在 PR 里说明
多人共用的开发分支不要
main / master / release/*绝对不要,走 PR

记住一条:强推的前提是只有你在往这个分支上推。