摘要

在使用 Git 将本地代码推送到 GitHub 时,有时会遇到 fetch firstremote contains work that you do not have locally 的错误。这个问题并不是代码写错了,而是因为远程仓库已经有了本地没有的提交。本文结合一次真实的 GitHub Pages 项目推送过程,完整分析问题原因、解决流程以及注意事项。

一、问题现象

在本地完成个人网站修改后,执行推送命令:

git push origin main

结果出现如下错误:

! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/账号名字/账号名字.github.io.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.

核心提示是:

remote contains work that you do not have locally

也就是说,远程仓库里有一些本地没有的提交。

二、为什么会出现这个问题?

这个问题的本质是:

本地分支和远程分支的提交历史不一致。

比如本地提交历史是:

A -- B -- 本地新提交

但 GitHub 远程仓库已经变成:

A -- B -- C -- D -- E

此时本地直接 push,Git 会担心你覆盖远程已有提交,所以拒绝推送。

常见原因包括:

  1. 在 GitHub 网页上编辑过文件。
  2. 在 GitHub 网页上传过文件。
  3. 另一台电脑或另一个本地目录推送过代码。
  4. GitHub Actions 自动生成并提交过文件。
  5. 本地仓库很久没有同步远程仓库。

三、如何确认当前状态?

可以先执行:

git status --short --branch

如果看到类似:

## main...origin/main [ahead 1, behind 12]

说明当前分支状态是:

  • ahead 1:本地比远程多 1 个提交。
  • behind 12:远程比本地多 12 个提交。

这就是典型的本地和远程分支分叉。

四、推荐解决方案

1. 拉取远程最新记录

先执行:

git fetch origin

fetch 只会把远程最新提交信息拉到本地,不会直接修改当前工作区,比直接 pull 更安全。

2. 使用 rebase 整理提交历史

执行:

git rebase origin/main

这一步会把本地提交移动到远程最新提交之后。

变基后的提交历史类似:

A -- B -- C -- D -- E -- 本地新提交

这样提交历史会更清晰。

3. 如果没有冲突,直接推送

git push origin main

五、如果 rebase 出现冲突怎么办?

有时执行:

git rebase origin/main

会出现冲突,例如:

CONFLICT (content): Merge conflict in index.html
CONFLICT (content): Merge conflict in assets/js/main.js
error: could not apply xxx...

这说明本地和远程都修改了同一个文件的同一部分,Git 无法自动判断该保留哪一份。

1. 查看冲突文件

git status

或者:

git diff --name-only --diff-filter=U

2. 打开冲突文件

冲突内容通常长这样:

<<<<<<< HEAD
远程分支中的内容
=======
本地提交中的内容
>>>>>>> commit-id

需要手动选择保留哪部分,然后删除这些冲突标记:

<<<<<<< HEAD
=======
>>>>>>> commit-id

3. 标记冲突已解决

git add 冲突文件路径

例如:

git add index.html assets/js/main.js assets/css/main.css

4. 继续 rebase

git rebase --continue

如果还有冲突,继续重复上述步骤,直到 rebase 完成。

六、最终推送

rebase 完成后,再次查看状态:

git status --short --branch

如果看到:

## main...origin/main [ahead 1]

说明本地已经基于远程最新代码,只多了一个本地提交。

此时执行:

git push origin main

即可成功推送。

七、完整命令流程

git status --short --branch

git fetch origin

git rebase origin/main

# 如果出现冲突,手动解决后执行:
git add .
git rebase --continue

# rebase 完成后推送:
git push origin main

八、不要轻易使用 git push -f

有些人遇到 push 被拒绝后,会直接使用:

git push -f origin main

这非常危险。

git push -f 会强制覆盖远程分支,可能导致远程已有提交丢失。

除非你非常确定远程提交可以被覆盖,否则不要在重要仓库中随意使用强制推送。

九、额外提示:TLS certificate verification has been disabled

推送时还可能看到这样的警告:

warning: TLS certificate verification has been disabled!
warning: HTTPS connections may not be secure.

这个警告不是 push 被拒绝的原因。

它表示 Git 的 HTTPS 证书校验被关闭了,存在安全风险。

可以执行:

git config --global http.sslVerify true

然后检查配置:

git config --get --show-origin http.sslVerify

如果仍然显示为 false,说明还有其他配置文件覆盖了这个设置,需要继续排查。

十、总结

这次问题的本质是:

远程仓库有本地没有的提交,本地又有新的提交,导致 Git 无法直接 push。

正确处理思路是:

  1. 先使用 git fetch origin 获取远程最新提交。
  2. 再使用 git rebase origin/main 把本地提交接到远程最新提交之后。
  3. 如果出现冲突,手动解决冲突。
  4. 最后执行 git push origin main 推送。

一句话总结:

Git push 被 rejected,不代表代码有问题,大多数时候只是本地分支没有同步远程最新提交。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐