应先 git fetch origin 再根据是否有未推送提交选择 git reset --hard origin/main 或 git rebase origin/main;直接 git pull 会失败,因远程强推导致历史重写、无共同祖先。

git pull 失败:remote rejected,提示 non-fast-forward
远程分支被别人用 git push --force 强推过,你的本地分支指针还停在旧提交上,此时执行 git pull origin main 会失败,报错类似:fatal: refusing to merge unrelated histories 或直接卡在“non-fast-forward”拒绝合并。这不是普通冲突,是历史被重写导致的同步断裂。
根本原因是:远程分支的提交链被强制替换(比如 rebase 后强推),你本地的 main 分支不再有共同祖先,Git 默认拒绝这种“断层式”合并。
- 别硬试
git merge --allow-unrelated-historie—— 这会把两段完全无关的历史强行缝在一起,产生大量冗余提交和混乱的 commit 图 - 优先用
git fetch拉取远程最新状态,再决定如何对接,而不是直接git pull - 确认是否真需要保留本地未推送的提交:如果只是临时改动或已备份,直接重置更干净
git fetch + git reset --hard 替换本地分支
适用于:你本地没有重要未推送提交,或这些提交已通过其他方式备份(如 stash / 新分支保存)。目标是让本地分支完全对齐远程最新状态。
操作步骤:
- 运行
git fetch origin,把远程最新main提交拉到本地origin/main引用 - 执行
git reset --hard origin/main,将当前分支头(HEAD)强制指向远程最新提交 - 检查结果:
git log --oneline -5应与git log origin/main -5完全一致
⚠️ 注意:--hard 会丢弃工作区和暂存区所有未提交改动。如果还有未 git add 的修改,先 git stash 保存,reset 后再 git stash pop 恢复。
git fetch + git rebase 保留本地提交但重放到底层
适用于:你有若干本地提交(比如功能开发还没 PR),且希望它们“叠”在远程新历史之上,保持线性、不引入 merge 提交。
操作流程:
-
git fetch origin获取远程最新origin/main -
git rebase origin/main将你本地分支上的提交,逐个变基到origin/main顶端 - 如果变基过程中出现冲突,解决后
git add+git rebase --continue,重复直到完成 - 完成后,
git push --force-with-lease origin main推送(注意不是--force,更安全)
关键点:rebase 不是合并,而是“重演”——它把你的提交按顺序重新应用一遍。如果远程已被强推,这比 merge 更符合“延续开发”的直觉,也避免污染主干历史。
为什么不用 git pull --rebase?
git pull --rebase 看似方便,但它等价于 git fetch + git rebase @{u},而 @{u}(上游分支)可能仍指向旧的远程引用(尤其在强推后未刷新时),导致 rebase 目标错误,甚至把提交重放到错误位置。
更可靠的做法是显式指定目标:git fetch origin → git rebase origin/main。这样能确保你清楚知道重放起点,也方便在出错时中断、检查、重试。
强推后的同步难点不在“怎么拉”,而在“要不要保留本地提交”以及“以什么逻辑接续”。跳过 fetch 直接 pull,或盲目用 allow-unrelated,往往让问题从“同步失败”变成“历史混乱”,后续 cherry-pick、bisect、回滚都会变难。











