git push提示“non-fast-forward”或“rejected”的根本原因是远程分支有新提交而本地未同步,git为防覆盖他人工作默认拒绝非快进更新。

为什么 git push 会提示 “non-fast-forward” 或 “rejected”
根本原因是远程分支的最新提交不在你的本地分支历史中——换句话说,别人已经往远程推了新提交,而你本地还停留在旧版本上。Git 默认拒绝覆盖这种“非快进”更新,防止误删他人工作。
常见触发场景:git pull 没做就直接 git push;多人协作时队友先推送了;自己在其他机器改完又没同步就切回原环境推送。
- 错误典型提示:
! [rejected] main -> main (non-fast-forward)或! [remote rejected] dev -> dev (refusing to update checked out branch) - 注意第二种带
refusing to update checked out branch的,是远程仓库被设为裸仓以外的普通工作目录(极不推荐),需单独处理 - 这不是网络或权限问题,和 SSH/HTTPS 认证成功与否无关
正确做法:先拉取再合并,而不是强制推送
绝大多数情况应该用 git pull 同步变更,让 Git 自动尝试 fast-forward 或创建 merge commit。
如果本地有未提交修改,git pull 可能失败,此时优先考虑:
- 运行
git status确认当前状态,尤其留意是否有 untracked / modified 文件 - 若只是暂存了改动但没提交,可先
git stash→git pull→git stash pop - 若已提交但不想产生 merge commit,可用
git pull --rebase,它把你的本地提交“重放”到远程新基线上,保持线性历史 - 避免无脑
git push --force,它会抹掉远程他人提交,协作中等同于删库跑路
git push --force-with-lease 什么情况下能用
仅当你确认远程分支只有你自己在写、且你只是想覆盖自己上次推送的“临时提交”(比如修正 commit message、撤回一个错推的调试提交)时,才考虑这个命令。
它比 --force 安全,因为会检查远程引用是否和你本地记录的一致——如果别人在你 fetch 之后又推了,它就会中止,避免静默覆盖。
- 使用前必须先
git fetch(或git pull --rebase),确保你知道远程当前 HEAD 是什么 - 不要对
main/master这类保护分支使用,CI/CD 流水线可能已基于旧提交运行 - 某些平台(如 GitHub)默认禁止 force-push 到 protected branches,即使加
--force-with-lease也会被拒绝
远程是普通工作目录导致的 “refusing to update checked out branch” 怎么办
这是 Git 的安全限制:不允许向一个已检出分支(即远程仓库里 git status 显示有工作区)推送。根本解法是让远程变成裸仓库(bare repo)。
如果你控制远程服务器,立刻执行:
cd /path/to/remote/repo git config --bool core.bare true
然后删掉所有工作区文件(rm -rf *,除 .git 外),再 mv .git/* . && rm -rf .git 把内容提一层——或者更稳妥:重新 git clone --bare 一份。
- 如果远程是共享文件夹(比如 SMB/NFS),且无法改配置,唯一临时办法是登录远程机器,手动
git checkout切走目标分支(例如切到dev),再推送,但这治标不治本 - 任何文档里教你在远程运行
git config receive.denyCurrentBranch ignore的方案,都属于埋雷,会导致远程工作区和 Git 数据库不一致,后续git status显示混乱
真正麻烦的从来不是命令记不住,而是分不清“我该同步别人”和“我要覆盖别人”的边界。每次看到 rejected,先停三秒看一眼 git log --oneline --graph --all,比翻十篇教程都管用。











