遇到 Git push 被拒绝且提示 non-fast-forward 时,说明本地分支落后于远程分支。最稳妥的做法是先拉取远程更新合并后再推送,除非你明确知道远程历史可以被覆盖。
典型报错信息
$ git push origin main
To github.com:user/repo.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:user/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.先说结论:这是本地分支落后于远程分支的保护机制,优先选择拉取合并,谨慎使用强制推送。
- 先确认:检查本地与远程提交历史的差异,确认是否有他人提交
- 先处理:使用 git pull 整合远程变更(推荐 merge 模式),解决冲突后再 push
- 再验证:查看提交日志确保历史线性或符合预期,再执行推送
解决方案一:合并更新(安全推荐)
适合团队协作的公共分支,保留完整的合并记录,避免改写历史。
# 1. 拉取远程更新并合并
git pull origin <分支名>
# 2. 如果有冲突,解决后提交
git add <冲突文件>
git commit -m "resolve conflict"
# 3. 推送本地提交
git push origin <分支名>解决方案二:变基更新(历史整洁)
适合个人分支或功能分支,保持提交历史线性。注意:不要在公共分支上使用。
# 1. 拉取远程更新并变基
git pull `--rebase` origin <分支名>
# 2. 如果有冲突,解决后继续
git add <冲突文件>
git rebase `--continue`
# 3. 推送本地提交
git push origin <分支名>方案对比与选择
- Merge 模式:生成合并提交节点,历史真实反映开发过程,适合主分支(main/master)。
- Rebase 模式:变基提交节点,历史呈直线,适合个人功能分支,便于代码审查。
怎么验证是否生效
推送完成后,运行 git status 确认显示“你的分支与 origin/分支名 同步”。再次查看日志 git log `--oneline` -5,确认最新的提交哈希与远程一致。如果是团队协作,通知同事拉取最新代码,确保大家基准一致。
常见坑
- 慎用强制推送:除非你确定远程历史可以丢弃(例如私有分支重构),否则不要用
git push `--force`。这会覆盖远程记录,导致队友代码丢失。 - 变基公共分支:不要对已经推送到公共仓库的分支进行变基(rebase),这会改变提交哈希,导致他人拉取时出现混乱。
- 忽略冲突:解决冲突时不要直接跳过,必须确保代码逻辑正确,否则可能引入隐蔽的 Bug。
参考来源
- Git 官方文档 - git-push: https://git-scm.com/docs/git-push
- Pro Git 中文版 - 变基: https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA