git push --force与非快进更新的区别及命令行为对比
一、git push --force 和非快进更新的核心区别
先把概念理清楚:所谓「非快进更新」,就是当你的本地分支和远程分支的提交历史分叉了——比如你本地埋头改代码的时候,同事已经往远程分支推了新提交。这时候你用普通的git push,Git会直接拒绝你,因为它默认不允许你覆盖远程那些你本地没有的提交,这就是非快进更新被阻止的场景。
而git push --force呢?它是直接跳过Git的非快进检查,硬把远程分支的指针拽到你本地分支的当前提交上,远程分支上所有你没同步的提交都会被覆盖掉,相当于直接「抹掉」了别人的工作,风险特别高,除非你明确知道自己在做什么(比如刚推了个错误提交,要立刻撤回去)。
两者的核心差异说白了就是:
- 非快进更新(正常push被拒):Git逼你先把本地和远程的历史整合好(比如用
git pull --rebase把你的提交变基到远程最新提交上面,或者用git merge合并),确保不会丢数据,之后才能推送。 git push --force:不管三七二十一,直接覆盖远程,完全不考虑远程有没有新内容,极易造成数据丢失。
二、git push --force origin master:master 和 git push origin +master:master 是否完全相同?
大部分日常单分支推送的场景下,这俩命令确实没区别——都是把远程master强制改成你本地master的样子。但在一些特定场景下,它们的行为会不一样:
1. 一次性推送多个分支时
--force是全局生效的,只要你这次push涉及的分支,都会被强制覆盖;而+是只针对单个分支的强制标记,其他分支还是会走正常的非快进检查。
举个例子:
- 如果你跑
git push --force origin master develop:远程的master和develop都会被强制覆盖,不管这俩分支有没有历史分叉。 - 但如果你跑
git push origin +master develop:只有master会被强制更新,develop还是会被Git检查——如果develop和远程分叉了,Git会直接拒绝推送这个分支。
2. 配合push.default配置时
旧版本的Git默认push.default是matching,意思是推送所有和远程同名的本地分支。这时候git push --force会把所有同名分支都强制推上去;而git push origin +master:master只会处理指定的master分支,完全不碰其他分支。
3. 服务器端分支保护规则的特殊情况
有些Git服务器(比如GitHub、GitLab)会有分支保护设置,比如禁止全局的--force推送,但允许针对单个分支的+标记推送(这种情况很少见,但理论上存在)。这种场景下,--force会被服务器拦截,而+标记的命令能正常执行。
总结一下
- 非快进更新是Git的安全防护,防止你误删远程提交;
git push --force是破防操作,一定要谨慎用。 - 单分支推送时,两者效果一致;但多分支推送或特定配置下,
+更精准(只针对指定分支),--force是一刀切(所有推送分支都强制)。
内容的提问来源于stack exchange,提问作者Number945

