ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

git push 报错 pre-receive hook declined:从权限到分支保护的排查路径与 TaoToken 配置记录

git push 报错 pre-receive hook declined:从权限到分支保护的排查路径与 TaoToken 配置记录 1. 从一次真实的 push 被拒说起pre-receive hook declined 到底是什么git push敲下去终端没有像往常一样滚动出Writing objects的进度条而是直接甩回来一行红字remote: GitLab: You are not allowed to push code to protected branches on this project. ! [remote rejected] main - main (pre-receive hook declined) error: failed to push some refs to gitgitlab.example.com:team/repo.git如果你第一次遇到pre-receive hook declined很容易以为是网络问题或者本地仓库坏了于是反复git push、删掉远程重新添加、甚至重装 Git结果报错一字不变。其实这个报错跟网络、跟本地仓库状态基本无关它是服务端主动拒绝你的推送。pre-receive是 Git 服务端的一个钩子hook。当你的git push把对象传到服务端后服务端在真正更新分支引用之前会先运行这个钩子脚本。脚本会拿到你这次推送涉及的所有引用变更逐条校验你有没有权限推这个分支、这个分支是不是受保护的、提交信息是否符合规范、有没有大文件、有没有触发 CI 门禁。只要有一条不通过脚本返回非零退出码Git 就会把整个推送回滚并告诉你pre-receive hook declined。所以这个报错是一个笼统的“服务端校验失败”信号真正的原因藏在remote:开头的那几行提示里。排查的核心思路就是先读remote:日志定位是哪一类校验挂了再对症处理。常见的成因可以归成三类分支保护规则拦截、账号 push 权限不足、hook 脚本自定义校验提交信息格式、文件大小、签名等不通过。这篇文章面向的是本地推送失败、想快速定位并恢复推送的开发者。我会按“读日志 → 查权限 → 查分支保护 → 查 hook 脚本 → 用统一通道验证”的顺序把每一步的可复制命令和判断依据都写清楚。顺带记录一下我在用 TaoToken 统一管理 API Key 和 Base URL 时怎么把鉴权配置和 Git 推送排查串起来避免在多个工具之间来回切换配置。先明确一点pre-receive hook declined不是 Git 客户端的问题你在本地怎么折腾都没用。必须去服务端侧找原因。下面进入具体排查。2. 先读 remote 日志再动手定位 pre-receive hook declined 真实成因很多人一看到报错就去搜“pre-receive hook declined 怎么解决”搜到的答案五花八门因为不同平台、不同 hook 脚本给出的原因完全不同。正确的第一步永远是把完整的报错日志读全。2.1 用 GIT_TRACE 和 verbose 拿到完整服务端输出默认情况下Git 会把服务端返回的remote:行打印出来但有时候被截断或者你滚动太快没看清。可以加上 verbose 参数重推GIT_TRACE1 GIT_CURL_VERBOSE1 git push origin main 21 | tee push.log如果你用的是 SSH 协议GIT_CURL_VERBOSE不生效改用GIT_TRACE_PACKET1 GIT_TRACE1 git push origin main 21 | tee push.log然后重点看push.log里所有以remote:开头的行。举几个真实例子remote: GitLab: You are not allowed to push code to protected branches on this project.这是 GitLab 的分支保护拦截。remote: error: GH006: Protected branch update failed for refs/heads/main. remote: error: Required status check ci/build is expected.这是 GitHub 的分支保护 必需状态检查未通过。remote: Commit message does not match the required pattern: ^(feat|fix|docs|chore)(\(.\))?: .这是自定义 hook 在校验提交信息格式Conventional Commits。remote: File build/app.apk is 120.00 MB; this exceeds GitHubs file size limit of 100.00 MB这是大文件拦截。2.2 判断是“权限类”还是“规则类”读完日志后先做一个粗分类这决定了你接下来查哪里remote 日志关键词成因类别处理方向not allowed to push / protected branch分支保护平台侧调整保护规则或加白名单permission denied / you dont have permission账号权限找管理员加 Developer/Maintainer 角色does not match the required patternhook 脚本校验改提交信息或调整 hookexceeds the file size limithook 脚本校验移除大文件、用 LFSrequired status checkCI 门禁等 CI 通过或调整规则如果日志里只有一句干巴巴的pre-receive hook declined没有任何remote:提示那说明服务端的 hook 脚本没有输出友好信息或者输出被平台吞了。这时候你需要联系仓库管理员让他去服务端看 hook 脚本的日志通常在仓库的hooks/pre-receive或平台的审计日志里。2.3 确认你推的是哪个分支、哪个引用有时候你以为自己在推feature/xxx实际上本地main也一起被推上去了。用下面命令确认这次推送涉及哪些引用git push --dry-run origin main git rev-parse --abbrev-ref HEAD git branch -vv--dry-run会模拟推送但不真正传对象能提前暴露引用范围。如果发现本地main落后于远程、或者你误把main也带上了先切到正确的分支再推git checkout feature/my-change git push origin feature/my-change这一步能解决相当一部分“我明明推的是自己的分支”的困惑。确认清楚引用之后再进入权限和分支保护的排查。3. 分支保护与 push 权限排查可复制的 git 配置与平台操作定位到是分支保护或权限问题后处理分两条线平台侧调整规则本地侧确认身份和远程地址。平台侧的操作各平台不同但本地侧的命令是通用的。3.1 确认本地提交身份和远程地址先确认你用的账号是不是有权限的那个git config --get user.name git config --get user.email git remote -v如果user.email跟你平台账号绑定的邮箱不一致服务端可能识别不出你是谁。修正git config --global user.name your-name git config --global user.email your-emailexample.com远程地址也要确认协议和主机对不对git remote set-url origin gitgitlab.example.com:team/repo.git3.2 分支保护的处理方式分支保护是pre-receive hook declined最常见的成因。以 GitLab 为例进入Settings → Repository → Protected branches你会看到main、release/*这类分支被设为Protected允许推送的角色通常是Maintainer及以上。如果你只是Developer推送就会被拒。三种处理方式按推荐顺序第一种把自己的分支推成新分支走 Merge Request。这是最规范的做法不破坏保护规则git checkout -b feature/fix-push-issue git push origin feature/fix-push-issue然后在平台上发起 MR由有权限的人合并。第二种让管理员把你的账号加入白名单。GitLab 的保护分支设置里有Allowed to push一栏可以把特定用户加进去这样你就能直接推main。第三种临时取消分支保护。仅建议在个人项目或紧急情况下使用团队项目慎用因为保护规则本身是为了防止误推和绕过 CI。GitHub 的对应位置在Settings → Branches → Branch protection rules可以设置Require a pull request before merging、Require status checks to pass、Restrict who can push。如果你被Restrict who can push拦了同样需要管理员把你加进允许列表。3.3 用统一配置管理多仓库鉴权当你在多个仓库、多个平台之间切换时鉴权配置容易乱。我习惯用一个统一的 API 通道来管理 Key 和 Base URL减少在.gitconfig、环境变量、CI 配置之间反复改的麻烦。TaoToken 提供统一的 Base URL 和 Key配置一次就能在多个工具里复用。在项目里放一个.env或者本地配置文件把通道信息集中管理{ base_url: https://taotoken.net/api, api_key: sk-your-taotoken-key, model_id: claude-sonnet-4-5, timeout: 60 }如果你用的是 Claude Code 这类工具配置通常落在~/.claude/settings.json或项目级settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-taotoken-key, ANTHROPIC_MODEL: claude-sonnet-4-5 } }注意这里的三件套必须齐全Base URL Key Model ID。少任何一个工具要么报 401要么报 model not found。Base URL 用https://taotoken.net/api不要带多余的路径后缀。如果你用 Codex配置落在~/.codex/auth.json{ OPENAI_BASE_URL: https://taotoken.net/api, OPENAI_API_KEY: sk-your-taotoken-key, OPENAI_MODEL: gpt-5 }Cline 这类 VS Code 插件则在设置面板里填 Base URL、API Key、Model ID 三项。Cline 支持 MCP但注意不要让 MCP 直连生产数据库MCP server 的配置里只挂只读或测试环境。把这些配置集中管理的好处是当你在排查 Git 推送问题时如果同时需要调用模型做代码审查或生成提交信息不用再单独配一套鉴权。统一通道减少了“这个工具能连、那个工具连不上”的排查成本。4. 验证请求与成功结果一次完整的 push 恢复动作配置和规则都调整完之后需要一次完整的验证动作确认推送真的恢复了。下面是我实际用的一套流程。4.1 推送前的自检git status git log --oneline -5 git fetch origin git rebase origin/maingit fetchgit rebase是为了确保你的本地分支基于最新的远程分支避免因为落后太多被服务端拒绝有些 hook 会校验是否 fast-forward。4.2 执行推送并观察输出git push origin feature/fix-push-issue成功的输出应该类似Enumerating objects: 12, done. Counting objects: 100% (12/12), done. Delta compression using up to 8 threads Compressing objects: 100% (7/7), done. Writing objects: 100% (7/7), 1.23 KiB | 1.23 MiB/s, done. Total 7 (delta 3), reused 0 (delta 0), pack-reused 0 remote: remote: To create a merge request for feature/fix-push-issue, visit: remote: https://gitlab.example.com/team/repo/-/merge_requests/new?merge_request%5Bsource_branch%5Dfeature%2Ffix-push-issue remote: To gitlab.example.com:team/repo.git * [new branch] feature/fix-push-issue - feature/fix-push-issue关键看最后一行有没有[new branch]或main - main以及有没有remote rejected。如果remote:行变成了创建 MR 的提示说明推送已经通过 pre-receive 校验。4.3 用 API 通道做一次连通性验证如果你在排查过程中同时配置了 TaoToken 通道可以顺手验证一下通道是否正常。用 curl 发一个最小请求curl -s -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: sk-your-taotoken-key \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-5, max_tokens: 64, messages: [{role: user, content: reply with ok}] }正常返回会包含content字段和模型输出。如果返回 401说明 Key 不对如果返回 404说明 Base URL 或路径不对如果返回 model not found说明 Model ID 写错了。这三类错误和 Git 推送的排查逻辑其实一样先看返回信息再定位是鉴权、地址还是参数问题。4.4 确认远程分支状态推送成功后确认远程分支确实更新了git ls-remote origin feature/fix-push-issue git log origin/feature/fix-push-issue --oneline -3git ls-remote会返回远程引用的 SHA跟你本地git rev-parse HEAD对比一致就说明推送落地了。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth排查过程中会遇到一些高频报错这里逐个对照。5.1 401 Unauthorizedremote: HTTP Basic: Access denied fatal: Authentication failed for https://gitlab.example.com/team/repo.git这是 Git 层面的 401通常是用 HTTPS 协议时密码或 token 过期。处理git config --global credential.helper store git remote set-url origin gitgitlab.example.com:team/repo.git改用 SSH 协议可以绕开 HTTPS 的 token 过期问题。如果是 API 通道的 401检查x-api-key或Authorization头是否带对Key 有没有多余空格。5.2 local proxy failedfatal: unable to access https://...: Failed to connect to 127.0.0.1 port 7890: Connection refused这是本地代理配置残留导致的。检查 Git 的代理设置git config --global --get http.proxy git config --global --get https.proxy如果有输出清掉git config --global --unset http.proxy git config --global --unset https.proxy同时检查环境变量HTTP_PROXY、HTTPS_PROXY是否指向了一个已经关闭的本地端口。这类问题在切换网络环境后特别常见。5.3 reading choices 相关报错error: reading choices: unexpected end of JSON input这类报错通常出现在调用模型 API 时返回体不是合法 JSON。原因可能是 Base URL 配错请求打到了错误的路径返回了 HTML 错误页。检查 Base URL 是否为https://taotoken.net/api不要多加/v1或/chat/completions之类的后缀具体路径由工具自己拼接。5.4 OAuth 相关报错OAuth token expired, please re-authenticate如果你用的是 Claude Code 或 Codex 的 OAuth 登录方式token 过期后需要重新登录。但如果你已经切换到 API Key 模式就不应该再走 OAuth。检查配置文件里是否同时存在 OAuth 和 API Key 两套凭据冲突时以 API Key 为准把 OAuth 相关字段删掉。5.5 三件套缺失导致的连锁报错不管是 Git 平台还是 API 通道配置类问题的根源往往是“三件套”不全。对照检查组件Git 场景API 通道场景地址remote URLBase URL凭据SSH Key / TokenAPI Key目标分支名Model ID任何一项缺失或写错都会表现为“连不上”或“被拒绝”。排查时按这个表逐项核对比盲目搜索报错信息高效得多。6. 把排查路径固化成习惯统一通道与快速恢复pre-receive hook declined本身不可怕可怕的是没有排查路径每次遇到都从头搜一遍。把上面的流程固化成习惯先读remote:日志分类再查分支保护和权限然后确认三件套配置最后做一次完整推送验证。对于经常在多个仓库、多个工具之间切换的开发者我建议把鉴权和通道配置集中管理。TaoToken 的统一 Base URL 和 Key 可以同时服务于 Git 辅助工具、代码审查、提交信息生成等场景减少重复配置。需要新建 Key 或查看用量时去控制台操作想先验证模型通道是否正常可以用模型对话页面发一条测试消息如果是长期编码或 Agent 场景Coding Plan 会更合适。具体入口新建和管理 API Keyhttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档和参数说明https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite模型对话验证通道https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite长期编码与 Agent 场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite控制台查看用量https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite最后留一个我踩过的坑有一次推送被拒日志只显示pre-receive hook declined没有任何remote:提示。折腾了半天权限和分支保护都没问题最后发现是服务端 hook 脚本里有一条“提交必须带 Jira 单号”的自定义校验而我的提交信息里没写。所以当常规排查都走不通时直接找仓库管理员看 hook 脚本内容往往是最快的路径。
返回列表