![git提交报错 ! [remote rejected] master -> master (pre-receive hook declined) 的排查与解决:把 pre-receive hook 配](http://pic.xiahunao.cn/yaotu/git提交报错 ! [remote rejected] master -> master (pre-receive hook declined) 的排查与解决:把 pre-receive hook 配)
1. 推送被拒的真实场景pre-receive hook 到底在拦什么你敲下git push origin master终端没有出现熟悉的Writing objects: 100%而是甩出一行红字! [remote rejected] master - master (pre-receive hook declined) error: failed to push some refs to gitgithub.com:xxx/xxx.git这个报错的核心含义是你的提交在本地完全合法但服务端的 pre-receive 钩子hook在接收前把它拦下来了。pre-receive hook 是 Git 服务端在「接收推送」这个动作真正落库之前执行的最后一道校验脚本它运行在远端仓库里而不是你的电脑上。只要它返回非零退出码整批推送就会被整体拒绝一个对象都不会写入。它和另外两个常见钩子的区别值得先理清钩子运行位置触发时机能否阻止推送pre-commit本地commit 前能本地拦截pre-receive服务端push 接收前能整批拒绝update服务端每个分支更新前能按分支拒绝post-receive服务端接收完成后不能仅通知所以看到pre-receive hook declined你要排查的方向不在本地 Git 命令写错而在「远端仓库配置了哪些规则」。最常见的四类拦截原因第一类是大文件超限。GitHub 单文件硬上限 100MB超过直接拒绝仓库总体积、单次推送体积也有软限制。很多人新建仓库后把数据集、压缩包、模型权重一起git add .第一次推送就撞墙。第二类是分支保护规则。master/main 被设为 protected branch 后禁止 force push、禁止直接推送、要求 PR 审核、要求状态检查通过。你本地直接推 master服务端 hook 判定不合规。第三类是提交信息规范。企业 GitLab、Gitea 常配置 commit message 必须匹配^(feat|fix|docs|chore):这类正则或者必须关联 issue 号如#123。信息不合规hook 拒绝。第四类是服务端自定义脚本。比如禁止提交.env、禁止提交超过 N 个文件的单次推送、禁止特定用户推送特定分支。我试过最坑的一种情况报错信息里只写了pre-receive hook declined但真正原因藏在服务端返回的上一行或下一行。GitHub 会额外打印remote: error: File xxx is 120.00 MB; this exceeds GitHubs file size limit of 100.00 MBGitLab 会打印remote: GitLab: You are not allowed to push code to protected branches。先完整读一遍 remote: 开头的每一行90% 的排查时间能省下来。这一篇就围绕这个报错从定位、清理本地缓存、配置规范、到把远端校验相关的 Key/API 通道统一到 TaoToken 做验证推送给你一套能直接复制的流程。适合刚建仓库就推不上去的新手也适合被分支保护卡住的老手。2. TaoToken 前置把校验通道和 Key 统一起来在动手清理大文件和改 hook 规则之前先把「推送验证」这条链路的环境准备好。很多同学排查到一半发现本地 git 配置、远端 hook、以及调用模型做提交信息规范校验的 API Key 散落在三四个地方改一处忘一处验证结果自然对不上。TaoToken 在这里的角色是统一的 Key/API 通道你本地脚本、CI 里的提交信息检查、以及需要调用模型生成规范 commit message 的工具都可以走同一个 Base URL 和同一把 Key避免「本地能推、CI 拒绝」这种环境不一致导致的假性 hook 报错。先拿到入口。控制台地址是https://taotoken.net/console登录后在 API Keys 页面创建一把 Key。创建时注意两点一是权限范围选最小可用只勾选你实际需要的模型二是 Key 只在创建时完整显示一次复制后立刻存进密码管理器。拿到 Key 之后你需要记住三个核心参数后面所有配置都围绕它们Base URLhttps://taotoken.net/apiAPI Keysk-开头的那串Model ID按你实际调用的模型填比如claude-sonnet-4-5或gpt-4o如果你用的是 Claude Code 这类命令行编码工具它读取的是环境变量如果你用的是 Cline、Cursor 这类编辑器插件它读取的是插件设置里的 Base URL Key Model 三件套。无论哪种三件套必须同时正确只填 Key 不填 Base URL 是最常见的 401 来源。这里要强调一个排查思路pre-receive hook declined本身和 TaoToken 没有直接因果关系hook 是 Git 服务端的事。但当你需要用模型自动校验提交信息是否符合规范、或者在 CI 里调用模型做代码检查时通道不统一就会引入新的失败点。把 Key 和 Base URL 收敛到一处能让「到底是 hook 拒绝还是 API 拒绝」一眼分清。文档入口在https://taotoken.net/doc里面有各语言 SDK 的接入示例。建议先跑通一次最小请求确认 Key 有效再去处理 Git 推送问题这样排查链路是干净的。3. 可复制配置本地 git 片段与 hook 规则对照这一节给你能直接粘贴的配置。分三块清理大文件的本地 git 命令、提交信息规范配置、以及统一 Key 通道的 settings 片段。3.1 清理已进入缓存的大文件报错提示大文件名后直接rm再 commit 是无效的因为git add已经把大文件写进了本地对象库。必须用filter-branch从历史里彻底移除。假设报错文件是crawler/zk-crawler.rargit filter-branch --force --index-filter \ git rm -rf --cached --ignore-unmatch crawler/zk-crawler.rar \ --prune-empty --tag-name-filter cat -- --all执行完再修正提交并强推git commit --amend -C HEAD git push origin master --force强推后清理本地残留对象避免下次又被打包进去rm -rf .git/refs/original/ git reflog expire --expirenow --all git gc --prunenow如果你不确定仓库里还有哪些大文件先扫一遍git rev-list --objects --all | \ git cat-file --batch-check%(objecttype) %(objectname) %(objectsize) %(rest) | \ awk /^blob/ {print $3, $4} | sort -nr | head -20这条命令列出历史中体积最大的 20 个对象单位是字节。超过 100MB104857600 字节的都要处理。3.2 提交信息规范配置如果 hook 校验的是 commit message 格式本地先自查。用 commit-msg 钩子做本地预检避免推到远端才被拒cat .git/hooks/commit-msg EOF #!/bin/sh MSG$(head -1 $1) PATTERN^(feat|fix|docs|style|refactor|test|chore)(\(.\))?: .{1,} if ! echo $MSG | grep -qE $PATTERN; then echo commit message 不符合规范: $MSG echo 示例: feat(login): 增加短信验证码 exit 1 fi EOF chmod x .git/hooks/commit-msg这样不合规的信息在本地就被拦下不会走到远端 pre-receive。3.3 统一 Key 通道的 settings 片段把模型调用的三件套写进项目级配置CI 和本地共用。以 JSON 为例放在项目根目录的.taotoken/settings.json{ base_url: https://taotoken.net/api, api_key: sk-你的Key, model_id: claude-sonnet-4-5, timeout: 60, retry: 3 }如果工具读取的是 TOML比如某些 CLI 的 coding-plan 配置[provider] base_url https://taotoken.net/api api_key sk-你的Key model_id claude-sonnet-4-5 [request] timeout 60 retry 3注意不要把真实 Key 提交进仓库。把settings.json加进.gitignore仓库里只放settings.example.jsonCI 里用环境变量注入。3.4 hook 规则对照表报错关键词拦截类型本地应对exceeds ... file size limit大文件filter-branch 清理protected branch分支保护走 PR 或临时解保护commit message信息规范commit-msg 本地预检not allowed to push权限检查账号角色GH001 / push declined体积超限拆分推送对照这张表先看 remote 输出里出现哪个关键词再选对应方案不要盲目强推。4. 验证请求确认推送一次性通过配置改完进入验证环节。验证分两步先确认 Key 通道可用再确认 Git 推送成功。4.1 验证 Key 通道用 curl 发一个最小请求确认 Base URL 和 Key 都对curl -s -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 回复 OK}], max_tokens: 10 }返回里出现choices数组且内容正常说明通道没问题。如果返回 401先查 Key 是否复制完整、是否带了多余空格如果返回local proxy failed说明 Base URL 写错或网络出口有问题检查是不是把https://taotoken.net/api写成了别的路径。4.2 验证 Git 推送清理完大文件、确认提交信息合规后执行推送git push origin master成功时你会看到Enumerating objects: 42, done. Counting objects: 100% (42/42), done. Delta compression using up to 8 threads Compressing objects: 100% (30/30), done. Writing objects: 100% (42/42), 1.2 MiB | 3.4 MiB/s, done. Total 42 (delta 12), reused 0 (delta 0) To github.com:xxx/xxx.git a1b2c3d..e4f5g6h master - master最后一行master - master没有rejected就是通过了。如果还是被拒回到第 5 节对照报错。4.3 用模型辅助生成规范提交信息如果你想让提交信息自动符合 hook 规范可以写个小脚本调用模型生成#!/bin/bash DIFF$(git diff --cached --stat) PROMPT根据以下改动生成一条符合 conventional commits 规范的提交信息只输出一行\n$DIFF curl -s -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_KEY \ -H Content-Type: application/json \ -d {\model\:\claude-sonnet-4-5\,\messages\:[{\role\:\user\,\content\:\$PROMPT\}],\max_tokens\:50} \ | grep -o content:[^]* | head -1把TAOTOKEN_KEY设为环境变量脚本就能复用同一把 Key。这样提交信息规范由模型保证本地 commit-msg 钩子兜底远端 pre-receive 自然不会再因格式拒绝。验证通过后建议再跑一次git log --oneline -5确认历史干净没有大文件残留的提交。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节把实际会撞到的报错逐个拆开。注意区分哪些是 Git hook 的错哪些是 API 通道的错别混在一起查。5.1 401 Unauthorized出现在 API 调用时不是 Git 报错。原因通常是Key 复制时带了首尾空格或换行Key 已过期或被删除请求头写成了Authorization: sk-xxx漏了BearerBase URL 和 Key 不属于同一环境排查echo -n sk-你的Key | wc -c看长度是否和创建时一致用curl -v看请求头实际发出的内容。5.2 local proxy failed这个报错说明请求根本没到达服务端卡在本地网络出口。常见于Base URL 写成了https://taotoken.net/api/多了一个斜杠导致路径拼接错误本地设置了 HTTP_PROXY 环境变量指向一个不可用的地址防火墙拦截了出站请求排查env | grep -i proxy看有没有残留代理变量curl -v https://taotoken.net/api看 TCP 连接是否建立。注意这里说的是排查本地网络配置不是让你去搭什么通道把环境变量清干净即可。5.3 reading choices 相关报错典型形式是cannot read property choices of undefined或reading choices。这说明代码拿到了响应对象但响应体里没有choices字段。原因请求体 JSON 格式错误服务端返回了错误对象而非正常响应model 字段填了不存在的模型名响应被中间层改写排查先把原始响应打印出来console.log(JSON.stringify(resp))看实际返回结构。多数情况是 model ID 拼错。5.4 OAuth 相关报错如果你用的是 Claude Code 或类似工具它可能走 OAuth 流程而非纯 API Key。报错形式如OAuth token expired或invalid_grant。处理方式重新执行登录命令刷新 token确认工具版本支持当前认证方式如果工具同时支持 API Key 和 OAuth优先用 API Key 模式配置更稳定5.5 Git 侧报错对照报错原因处理pre-receive hook declined服务端规则拒绝读 remote 输出定位failed to push some refs远端有新提交先 pull --rebaseremote: error: GH001仓库超 1GB清理历史大文件protected branch hook declined分支保护走 PR 流程non-fast-forward历史分叉确认后 force push排查顺序建议先看 remote: 开头的完整输出 → 判断是 hook 规则还是网络 → 再决定改本地还是改远端。不要一看到 rejected 就 force push强推解决不了 hook 规则问题反而可能丢提交。6. 把校验链路收敛到统一通道走到这里pre-receive hook declined的排查路径已经完整读 remote 输出定位规则类型大文件用 filter-branch 清理提交信息用本地钩子预检分支保护走 PRAPI 通道用统一 Key 验证。真正让排查变快的不是记住某一条命令而是把变量收敛。Git 推送失败的原因可能有三层本地对象库、远端 hook 规则、以及调用模型做校验时的 API 通道。前两层是 Git 本身的事第三层如果 Key 和 Base URL 散落各处就会制造「明明本地能推、CI 却拒绝」的假象。把模型调用的三件套——Base URLhttps://taotoken.net/api、API Key、Model ID——统一到一处配置本地脚本和 CI 共用同一把 Key验证请求时先跑通最小 curl再去推 Git。这样任何一次失败你都能立刻判断是 hook 拒绝还是通道拒绝。需要创建 Key 的话控制台在https://taotoken.net/console接入示例在https://taotoken.net/doc。如果你要长期在编码流程里用模型做提交信息规范、代码检查可以看下 coding-plan 方案把调用额度固定下来避免每次临时申请 Key 打断排查节奏。推送通过后记得git gc收尾让仓库保持干净。