git push 报错怎么办:先分清是地址、凭据还是分支,别急着重装(2026)

Updated on in 实用技巧

先说结论:git push 报错别急着重装,八成是这三个原因之一

git push 失败时,最常见的反应是去网上搜那串报错原文,然后照着别人帖子里的命令一条条敲,最后把 .git 删了重新 clone。其实大多数 push 报错都能归到三类:远端地址变了、凭据失效了、分支没对上。这篇按「花多少时间、多大概率解决」排序,先做 30 秒就能排除的,再往深了查。

一、30 秒先看这个:你 push 的到底是不是你以为的那个仓库

最容易踩的是「仓库地址和你想的不一样」。很多人配置了多个远端,或者换过托管平台,push 时一直推到旧地址,报错却是「Authentication failed」或「Could not resolve hostname」。

先看当前远端配的是什么(实测,Windows 和 macOS 的命令完全一样):

git remote -v

输出形如:

origin  https://github.com/sky/blog.git (fetch)
origin  https://github.com/sky/blog.git (push)

如果这里的地址和你现在要推的仓库对不上,改掉它:

git remote set-url origin https://github.com/你的用户名/仓库名.git

这条命令 5 秒就能跑完,却是「折腾一小时最后发现推到旧仓库」这类事故的解药。改完再 git push,很多时候直接就好了。

二、第二常见:凭据(密码/token)失效了

GitHub 从 2021 年 8 月起就不再接受账号密码做 HTTPS 推送(来源:GitHub 官方 blog 2021-08),必须用 Personal Access Token。很多报错的真实原因就是:仓库还是老的,但凭据过期了,或者当初存的就是已经作废的 token。

判断是不是凭据问题的两个信号:

  • 报错里出现 Authentication failed for 'https://github.com/...'
  • 或者 remote: Invalid username or password、403

macOS 和 Windows 会把凭据存在系统钥匙串/凭据管理器里,失效后要主动清掉才能重新弹输入框。以 Windows 为例,Git 默认用系统凭据管理器存储(实测):

git credential-manager erase

或者到「控制面板 → 凭据管理器 → Windows 凭据」里,找到 git:https://github.com 那条删掉,下次 push 就会重新要求输入用户名和 token。

一个关键点:填 token 时,用户名填你的 GitHub 用户名,密码框填 token,而不是把 token 当用户名填。这一步填错的人非常多。

如果你用的是 SSH 而不是 HTTPS,那要查的是密钥对不对得上:

ssh -T git@github.com

返回 Hi 用户名! You've successfully authenticated 就说明 SSH 通了;返回 Permission denied (publickey) 就是公钥没加进 GitHub 或本地密钥路径不对。

三、第三常见:本地分支和远端分支对不上

前两类都排除了,再看分支。常见的报错是:

fatal: The current branch main has no upstream branch.

或者 push 时提示远端有本地没有的提交,被拒绝(non-fast-forward)。这通常发生在:你 clone 下来之后别人也往同一个分支推了,或者你本地分支是从别的分支切出来的,跟远端不是一条线。

先同步远端再推(实测,这是处理「远端有新提交」最稳的顺序,先 pull 再 push 比强行 --force 安全得多):

git pull --rebase origin main
git push origin main

--rebase 会把你的本地提交「垫」在远端新提交之上,避免产生一次多余的 merge 提交。如果确实想覆盖远端(比如你本地是对的、远端那几笔是废的),才考虑强制推,但要明确知道代价:

git push --force-with-lease origin main

--force-with-lease 比裸 --force 安全(来源:Git 官方文档),它会在覆盖前检查远端是不是你上次看到的状态;如果别人在你看不到的时候推了新提交,它会拒绝执行,避免把别人的活冲掉。除非百分百确定远端那几笔提交是废的,否则不要用裸 --force。

四、五个我踩过的坑,都是上面三类的变种

  1. 改完 remote 还是报同样的错。 因为凭据也被缓存了,地址改了但 token 还是旧的。改地址和清凭据要一起做。

  2. 公司内网用 HTTPS push 到自建 GitLab,一直超时。 这多半不是 Git 的锅,是代理或防火墙。Git 会读 http.proxy 配置,内网地址被代理劫持了。临时关掉再试(实测):

    git config --global --unset http.proxy
    git config --global --unset https.proxy
    
  3. 报错 RPC failed; HTTP 413,大文件推不上去。 这是仓库里的文件超过了托管平台单文件大小限制。GitHub 是 100 MB(来源:GitHub 官方文档),超过会拒绝。这个坑比前两个少见,但一遇到就很耽误时间。

    解决思路两条路:大文件如果确实要版本化,用 Git LFS 管;如果是不小心 add 进来的误提交,从历史里清掉。这里重点说第一种,因为用 LFS 的人不多、文档又散:

    # 安装 LFS 后,初始化
    git lfs install
    # 把某种大文件类型交给 LFS 管
    git lfs track "*.zip"
    git add .gitattributes
    # 之后正常 add/commit/push,大文件会走 LFS 通道
    

    LFS 的核心(实测):它不在 Git 历史里存大文件本体,只存一个指针,真正的文件单独传。所以用 LFS 之前历史里已经误传的大文件,track 之后也救不回来,得用 filter-repo 或 filter-branch 重写历史——这一步属于进阶操作,动手前务必先备份 .git。

  4. SSH 换了端口还是连不上。 有些公司 Git 服务器改过 SSH 端口,不是默认 22。要在 ~/.ssh/config 里显式指定,git remote 的地址里也得写成 ssh:// 形式带端口。

    举例,如果服务器 SSH 端口是 2222,~/.ssh/config 里加:

    Host git.company.com
      Port 2222
    

    然后 remote 地址用 ssh://git@git.company.com:2222/group/repo.git 这种带端口的写法(实测,端口在 ssh:// 里要显式写出来,否则 config 里的 Port 不一定被读到的情形也有)。

  5. push 成功但 CI 里拉不到。 这是「分支名大小写」或「没推对分支」导致的。确认本地分支名和远端分支名完全一致,包括大小写。

  6. 同时干几件事,用 worktree 会清爽很多,但也带来新的 push 坑。 如果你习惯同时开几个分支开发,git worktree 能在同一仓库下开多个工作目录,不用反复 stash/checkout。但它有个坑:worktree 里改的东西,主仓库的 git status 看不到,很多人以为丢了、或者从主仓库 git push 时发现「没东西可推」。

    排查要点:先在主仓库跑 git worktree list,看有哪些 worktree 在工作(实测):

    git worktree list
    

    输出里除了主路径,还有你开的每个 worktree 的路径和所在分支。搞清楚改动在哪个 worktree 里,再决定从哪 push。另外 worktree 里的分支不能同时被两个地方 checkout,否则会报 fatal: 'xxx' is already checked out。

五、凭据这块,顺便把「为什么老是要重新登录」说透

很多人 push 一次输一次密码,烦得不行。这不是平台故意刁难,是凭据没有被正确缓存。不同系统的机制不一样,搞清楚自己用的是哪套,才能一劳永逸。

  • Windows + Git 官方安装包:默认走 Git Credential Manager,第一次登录后会写进系统凭据管理器,之后不用再输。如果每次都弹,多半是凭据管理器里存的 token 失效了,清掉重登一次就好。
  • macOS:走钥匙串(Keychain),Git 会把凭据存进去,同样一次登录长期有效。
  • Linux 或精简环境:可能没有装 credential helper,每次 push 都走内存里的临时凭据,会话结束就没了。

想确认当前用的是哪种,看一条配置(实测):

git config --global credential.helper
  • 输出 manager 或 manager-core:走 Git Credential Manager(Windows 常见)
  • 输出 osxkeychain:走 macOS 钥匙串
  • 输出为空:没配置,凭据不会持久化

如果输出为空,说明你每次 push 都要重新输,那就可以手动指定一个 helper。Windows 用 manager,macOS 用 osxkeychain:

git config --global credential.helper manager

配好之后,下次 push 登录一次,之后就不用了。这一步做完,凭据相关的报错会少一大半。

六、常见报错原文对照表:看到哪句,直接跳到哪一步

为了让你不用通读全文,我把最常见的报错原文和它的归属列成一张表。你在终端里看到哪句,就对号入座:

报错原文(关键词)归属直接跳
Authentication failed for 'https://...'凭据失效第二节
remote: Invalid username or password凭据失效第二节
remote: Permission to xxx.git denied凭据/权限第二节
fatal: unable to access ... Could not resolve host地址/网络第一节 + 第四节坑2
fatal: The current branch xxx has no upstream branch分支没关联第三节
! [rejected] ... (non-fast-forward)远端有新提交第三节
! [rejected] ... (fetch first)远端有新提交第三节
remote: Support for password authentication was removed用了密码没换 token第二节
error: RPC failed; HTTP 413大文件超限第四节坑3
Permission denied (publickey)SSH 公钥没配第二节

这张表本身就是一个最快的分流器:先看报错原文,再决定从哪一节看起,而不是从头读。

七、git push 之外,两个经常一起出现的兄弟问题

push 报错往往不是孤立的,它和两个问题经常一起出现,一并说清楚,省得你查完 push 又去查别的。

第一个:本地改了东西,但 git status 说干净。 这通常是改了却被 .gitignore 忽略了,或者改在了错误的目录。看某个文件到底被没被忽略:

git check-ignore -v 你怀疑的文件名

如果有输出,说明它命中了 .gitignore 的某条规则;没输出就是没被忽略。

第二个:clone 一个很大的仓库卡住不动。 这和我之前写过的「AI 写的 SQL 导致数据库死锁」是同一类「看着像卡住、其实要分层定位」的问题,思路都是先判断卡在哪一段再动手。大仓库可以先做浅克隆,只拉最近一次提交,速度快很多(实测):

git clone --depth 1 https://github.com/某仓库.git

等确定要完整历史了,再 git fetch --unshallow 拉全。

八、我的结论:什么情况重装 Git,什么情况别动

别急着重装 Git。 上面三类问题(地址、凭据、分支)没有一个靠重装能解决,重装只会把配置清掉,反而更难查。按这个顺序走,99% 的 push 报错在第二步就能定位:

  1. git remote -v 看地址对不对(30 秒)
  2. 判断是不是凭据失效,清掉重新登录(1 分钟)
  3. git pull --rebase 再 push(1 分钟)

适合重装 Git 的只有一种情况:Git 本身坏了,比如所有命令都报 fatal: not a git repository 但目录里明明有 .git,或者 Git 命令直接崩溃、版本混乱。这种情况极少,而且重装前也要先把 .git 目录备份好。

如果你是按网帖把 .git 删了重新 clone 才解决,那说明你其实丢掉了本地没 push 的提交——正确做法是先 git log 确认哪些没推上去,git stash 或切个分支把改动保住,再 clone。丢了工作区是最亏的,比 push 报错本身严重得多。

说到丢提交,我在本地部署和编译开源项目时也栽过类似的坑,比如当初折腾 DeepSeek Harness 的源码编译打包 时,就因为没先把本地改动分叉出来,白白返工了一轮。Git 的每一个「回退」「覆盖」操作,动手前都值得先想一句:这步会不会丢东西。

九、最后说一个很多人忽略的元问题:报错其实是分层的

写完这一篇,我想强调一个更根本的思路,它比上面任何一条具体命令都值钱。

Git 的报错几乎从来不是「Git 坏了」,而是「某一层的状态和你的预期不一致」。 地址是一层、凭据是一层、分支关系是一层、网络又是一层。绝大多数人查 push 报错的失败方式,是直接搜那串报错原文,然后照着帖子里的命令一条条试,试到哪条碰巧好了为止——这是「撞大运式排查」,运气好三分钟,运气不好一下午。

正确的方式是先判断自己卡在哪一层,再动手。判断分层最快的手段,其实就三条命令,各管一层:

git remote -v          # 看「地址层」对不对
git config --list      # 看「配置层」(含 credential.helper、http.proxy)对不对
git status && git log --oneline -5   # 看「分支层」:本地在哪、领先远端几笔

这三条跑完,绝大多数 push 报错该看哪一层、该改什么,心里就有数了,剩下的只是执行。

这个「先分层、再定位」的思路,跟我写过的其它排查类文章是一脉相承的——不管是排查 AI 写的 SQL 导致数据库死锁,还是给本地程序定位卡点,都是先画一条「卡在哪一段」的线,而不是上来就重装。工具会变、报错会变,但这个排查的框架是长期有用的。

所以这篇的最终结论可以再浓缩成一句:git push 报错,先跑 git remote -v 和 git config --list,再决定动不动手;别删 .git,别急着重装。

补充两个容易被忽略、但很省事的小习惯(实测):

  • 报错出来先看完整的第一行和最后一行,中间的调用栈多数时候可以忽略。真正的原因通常就藏在这两行里。
  • 养成 push 前先 git status 一眼的习惯,确认自己在哪个分支、有哪些改动待提交。很多人 push 失败,归根到底是没意识到自己当前不在以为的那个分支上——这个问题 5 秒就能在上游避免,比事后排查省一百倍的时间。