
1. 先别急着删仓库看清 remote rejected 到底在拒绝什么git push被 GitHub 拒绝报出remote rejected和repository rule violations很多人第一反应是网络问题或者权限不够反复重试、换网络、重新登录结果错误一模一样。其实这条报错跟网络没关系它是 GitHub 服务端在收到你的推送包之后逐条检查提交内容发现不符合仓库规则直接把整个 push 打回来了。remote rejected是结果repository rule violations是原因分类。GitHub 的仓库规则Repository Rules和推送保护Push Protection会在服务端拦截几类东西提交里含有被识别为密钥的字符串、提交信息不符合规范、文件体积超过限制、分支保护要求必须走 PR、提交者邮箱未验证等。你看到的GH013就是规则校验失败的错误码。这篇面向的是正在被这个报错卡住的开发者尤其是推送时终端刷出一大段remote: error: GH013却不知道从哪下手的人。我会把排查顺序拆成可复制的命令和逐项验证动作让你能定位到具体是哪个文件、哪一行、哪条规则触发的拒绝然后针对性修掉。整个过程不需要你懂 GitHub 内部实现照着敲命令看输出就行。另外说一个容易被忽略的点这类报错有时候不是代码本身的问题而是你本地 Git 配置、提交历史、甚至凭证通道的问题。如果你在用统一的 API 通道做模型调用或代码辅助推送环节的凭证和远端地址配置也可能互相干扰。下面会结合 TaoToken 的统一通道配置把「推送被拒」和「通道配置」两条线分开排查避免你把规则问题和接入问题混在一起。2. 前置准备用 TaoToken 统一通道管好凭证与接入配置在动手改提交之前先把「凭证从哪来、往哪走」这件事理清楚。很多remote rejected的排查之所以绕远路是因为本地同时存在多套凭证Git 的 credential helper、环境变量里的 token、IDE 插件里缓存的登录态还有模型调用通道的 API Key。它们混在一起时你改了一处另一处还在用旧值push 依旧被拒。TaoToken 在这里的角色是统一通道把模型对话、编码辅助、API 调用这些入口收敛到一套 Key 和一套地址上减少「这个 Key 是哪个环境的」这类混乱。它的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个地址不加 UTM 参数。你可以在控制台里生成和管理 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 列表页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。需要强调的是TaoToken 管的是模型调用和编码辅助的接入通道不是 Git 远端。你的git push目标仍然是 GitHub 仓库两者不要混为一谈。把通道配好是为了让你在排查推送问题时能确认「本地环境变量里没有残留的旧 Key 干扰 Git 凭证」同时让后续用模型辅助分析提交内容时有个稳定的调用入口。如果你只是偶尔用模型帮忙看报错用模型对话页就够了https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你长期做编码、跑 Agent 任务建议直接上 Coding Plan省得每次手动配https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Claude Code 相关配置看 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。配好之后先做一件事确认 Git 的凭证来源单一。执行下面这条命令看输出里有没有多个 helpergit config --show-origin --get-all credential.helper如果输出多行说明有多个凭证助手在抢。保留一个即可比如只留系统默认的git config --global --unset-all credential.helper git config --global credential.helper store这一步不是解决remote rejected的直接手段但它能排除「凭证错乱导致推送身份不对」这个干扰项。身份不对时GitHub 可能把你当成无权限用户报错形态和规则拒绝很像。3. 可复制配置逐项定位 repository rule violations 的触发点GitHub 的拒绝信息其实已经把线索给全了只是刷屏太快容易漏看。关键在remote:开头的那几行。以典型输出为例它会明确写出remote: error: GH013: Repository rule violations found for refs/heads/main. remote: - GITHUB PUSH PROTECTION remote: - Push cannot contain secrets remote: —— Alibaba Cloud AccessKey ID ———— remote: locations: remote: - commit: 40e3c6c07ca483573ea5077acb6d6d4426c0ef9a remote: path: tlogin/alioss.go:29这段告诉你三件事规则类型是 Push Protection触发原因是「提交包含密钥」具体位置是tlogin/alioss.go第 29 行涉及的是某云厂商的 AccessKey。你要做的就是按这个路径去定位。第一步把完整报错存下来别让它滚走git push origin main 21 | tee push-error.log然后从日志里提取所有path:行grep -n path: push-error.log这会列出所有被标记的文件和行号。逐个打开确认比如sed -n 25,35p tlogin/alioss.go看到明文密钥后处理方式有三种按你的实际情况选。第一种直接删掉代码里的密钥值改成从环境变量读取。这是最干净的做法// 修改前 accessKeyID : LTAI5txxxxxxxxxxxx accessKeySecret : xxxxxxxxxxxxxxxxxxxx // 修改后 accessKeyID : os.Getenv(ALIYUN_ACCESS_KEY_ID) accessKeySecret : os.Getenv(ALIYUN_ACCESS_KEY_SECRET)改完提交但注意如果这个密钥已经出现在历史提交里光改当前文件不够GitHub 扫的是整个推送包里的所有提交。你需要把历史里的密钥也清掉或者用下面的第二种方式。第二种如果这个密钥是测试用的假值或者你确认可以放行走 GitHub 给的许可链接。报错里会有类似https://github.com/xxx/yyy/security/secret-scanning/unblock-secret/xxxx的地址点进去按提示允许这次推送。这只对当前这次有效下次再推同样的内容还会被拦。第三种在仓库设置里关闭该规则的拦截。进入仓库的 Settings → Security → Secret scanning把 Push protection 关掉。但我不建议这么做因为关掉之后所有密钥都不会被拦风险很大。如果只是临时排查可以关掉验证完再打开。除了密钥repository rule violations还可能来自分支保护。比如规则要求main分支必须通过 PR 合并你直接 push 就会被拒。这种报错的文案不同通常是remote: error: GH006: Protected branch update failed for refs/heads/main. remote: error: Required status check ci is expected.遇到这种要么走 PR 流程要么在仓库 Settings → Branches 里调整规则。排查命令是看当前分支的保护状态git remote show origin输出里会显示main是否被保护、推送策略是什么。还有一种容易被忽略的是提交信息规则。有些仓库配置了 commit message 必须符合 Conventional Commits比如必须以feat:、fix:开头。你的提交信息是「update」这种就会被规则拒绝。验证方式是看报错里有没有commit message相关字样有的话用git commit --amend改掉再推。文件体积超限也会触发。GitHub 单文件限制 100MB超过直接拒。检查方式git rev-list --objects --all | git cat-file --batch-check%(objecttype) %(objectname) %(objectsize) %(rest) | awk /^blob/ {print $3, $4} | sort -nr | head -10这会列出仓库里最大的 10 个文件。如果发现大文件用git filter-repo或 BFG 清理历史。4. 验证请求确认修复后推送成功改完之后不要直接git push先本地验证一遍避免又被拒一次浪费时间。先确认工作区干净、提交已生成git status git log --oneline -3然后检查这次要推的提交里还有没有敏感字符串。用一个简单的模式匹配扫一遍git diff origin/main..HEAD | grep -iE accesskey|secret|password|token|api[_-]?key | head -20如果输出为空说明当前 diff 里没有明显敏感词。注意这只是粗筛GitHub 的检测更严格但能帮你排掉大部分明显问题。接着做一次 dry-run 推送看服务端反应git push --dry-run origin main--dry-run不会真正写入远端但会走完服务端的规则校验。如果这次没有remote rejected说明修复生效。如果还有报错会再次给出具体路径回到第 3 节继续定位。确认无误后正式推送git push origin main成功的输出类似Enumerating objects: 19, done. Counting objects: 100% (19/19), done. Writing objects: 100% (19/19), 11.99 KiB | 3.00 MiB/s, done. To https://github.com/yourname/yourrepo.git 40e3c6c..a1b2c3d main - main看到main - main且没有remote rejected就说明推送通过了。如果你在排查过程中需要模型帮你分析报错日志可以把日志贴到模型对话里https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它会帮你把remote:行里的关键信息提取出来省得你一行行看。长期做这类排查的话Coding Plan 更顺手https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。5. 本篇常见错排查这些坑我踩过第一个坑只改了当前文件没清历史提交。GitHub 扫的是推送包里所有 commit你改了最新一次提交但前几次提交里还有密钥照样被拒。验证方式是看报错里的commit:哈希是不是你最新那个。如果不是说明问题在历史里。清理历史用git filter-repo --path tlogin/alioss.go --invert-paths或者用交互式 rebase 把历史提交逐个改掉。改完历史后需要强制推送git push --force-with-lease origin main--force-with-lease比--force安全它会在远端有你没拉到的提交时拒绝覆盖。第二个坑以为关掉 Push Protection 就万事大吉。关掉之后确实不拦了但密钥已经泄露在提交历史里任何人 clone 都能看到。正确顺序是先轮换密钥去云厂商控制台把旧 Key 禁用、生成新 Key再清理历史最后才考虑是否重新开启保护。第三个坑凭证缓存导致推送身份不对。表现是报错里出现Permission denied或403而不是GH013。这时候清掉缓存重新登录git credential-cache exit git credential-store erase然后重新 push按提示输入新的凭证。第四个坑分支名写错。你本地是main远端默认分支是masterpush 时目标对不上报错形态也可能是 rejected。确认方式git branch -vv git remote show origin | grep HEAD branch两边不一致时要么改本地分支名要么明确指定推送目标git push origin main:master第五个坑把 TaoToken 的 API Key 和 Git 凭证搞混。有人在环境变量里设了GITHUB_TOKEN又设了模型通道的 Key结果 Git 读取时拿错了值。排查方式是看当前 shell 里有哪些相关变量env | grep -iE token|key|secret | sed s/.*/***/把值打码显示确认没有把模型通道的 Key 当成 Git token 用。TaoToken 的 Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Git 的凭证在系统钥匙串或~/.git-credentials里两者分开存放。第六个坑.gitignore没生效把本地配置文件推上去了。比如.env里有密钥你以为被忽略了其实之前已经git add过。检查方式git check-ignore -v .env git ls-files | grep -E \.env|config\.json如果.env出现在git ls-files输出里说明它已被跟踪需要先移除git rm --cached .env再提交。6. 把通道和推送分开管排查效率翻倍回到最开始的问题remote rejected和repository rule violations之所以让人头疼是因为报错信息量大、触发点分散。但拆开看无非是「规则拦了什么」和「你的配置对不对」两件事。规则拦的内容GitHub 已经在remote:行里告诉你了按path:和commit:定位即可配置对不对靠git config和env两条命令就能确认。我自己的习惯是推送前先跑一遍git push --dry-run让服务端先校验一次有问题当场暴露不用等正式推送再回滚。这个动作花不了几秒但能省掉很多「推了一半被拒」的尴尬。至于模型调用和编码辅助这条线用 TaoToken 统一通道把 Key 和地址收敛好就不会出现「这个 Key 是哪个环境的」这种问题。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 需要看模型对话的直接进 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 长期编码任务用 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。两条线各管各的排查时就不会互相干扰。最后留一个实用动作把这次报错日志和修复过程记到仓库的docs/troubleshooting.md里。下次再遇到类似拒绝直接翻记录比重新搜一遍快得多。