☰
git提交报错 ! [remote rejected] master -> master (pre-receive hook declined) 的排查与解决:把 pre-receive hook 配
2026/10/3 6:50:56 网站建设 项目流程

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 'git@github.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 GitHub's file size limit of 100.00 MB,GitLab 会打印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 URL:https://taotoken.net/api
  • API Key:sk-开头的那串
  • 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.rar:

git 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 --expire=now --all git gc --prune=now

如果你不确定仓库里还有哪些大文件,先扫一遍:

git rev-list --objects --all | \ git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \ awk '/^blob/ {print $3, $4}' | sort -nr | head -20

这条命令列出历史中体积最大的 20 个对象,单位是字节。超过 100MB(104857600 字节)的都要处理。

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.json,CI 里用环境变量注入。

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,漏了Bearer
  • Base 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 --rebase
remote: 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 清理,提交信息用本地钩子预检,分支保护走 PR,API 通道用统一 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收尾,让仓库保持干净。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询