
1. 先别急着改代码pre-receive hook declined 到底卡在哪git push到 master 时看到! [remote rejected] master - master (pre-receive hook declined)第一反应往往是「我代码写错了」其实这条报错跟你的 commit 内容基本无关它是服务端在真正写入仓库之前用一段叫pre-receive的钩子脚本把你的推送拦下来了。换句话说代码已经打包发到服务端了是服务端在「入库前安检」这一步说了不。这个钩子能拦的东西很多分支保护规则、推送权限、提交信息格式、大文件限制、签名校验、CI 门禁甚至仓库配额。所以同一个报错背后可能是完全不同的原因。我见过有人折腾一下午改 SSH key最后发现只是 master 被设成了 Protected Branch而他的角色是 Developer压根没资格直推。这篇面向的场景很具体你本地git push origin master被拒报的就是 pre-receive hook declined你想按「服务端钩子 → 分支保护 → 权限 → 提交规范」四条线逐一定位并且顺手把 TaoToken 的统一 Key/API 通道接进你的开发流里。适合刚接手一个陌生仓库、或者团队刚开了分支保护、又或者你在用自动化脚本推代码却突然被拦的开发者。下面每一步都给可复制的命令和配置你照着排查就行。2. 把 TaoToken 统一 Key 通道接进来先解决「用哪个凭证」的问题排查推送问题之前有个容易被忽略的点很多团队现在不止一个模型服务或 API 通道本地脚本、CI、编辑器插件各配各的 Key一出问题根本不知道是哪个凭证在生效。TaoToken 做的就是把这些统一到一个 Key 通道上官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。它的定位不是替代 Git 或编辑器而是给你一个统一的模型调用出口你申请一个 Key然后在 config.toml、settings.json 这类配置文件里指向同一个 base_url本地调试、脚本、Agent 都走这条通道。这样当推送被拦、你需要临时用模型帮忙分析钩子日志时不用再翻五个不同的 Key。接入前先做两件事。第一去控制台建 Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 建完在 API Keys 页面能看到明文只显示一次记得存好页面是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。第二确认你要接的是哪类工具如果是命令行里想让模型帮你读钩子报错用模型对话入口 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 如果是长期写代码、跑 Agent建议直接看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 额度模型更适合持续调用。注意TaoToken 是模型 API 通道不参与你的 Git 权限判定。它帮不了你「绕过」pre-receive hook但能帮你快速读懂服务端返回的钩子日志、生成规范的 commit message、写排查脚本。别把两件事混在一起。3. 可复制的配置骨架config.toml 与 settings.json下面给两份骨架一份给偏命令行的工具config.toml一份给偏编辑器/插件的工具settings.json。你把 Key 换成自己申请的那串即可base_url 统一指向 TaoToken。先看config.toml# ~/.taotoken/config.toml # TaoToken 统一 Key 通道配置骨架 [provider] name taotoken base_url https://taotoken.net/api api_key sk-你的TaoTokenKey timeout_seconds 60 [model] default claude-sonnet # 需要长上下文或复杂推理时切换 fallback gpt-4o [request] max_retries 3 retry_backoff_ms 800 # 排查 git 钩子日志时把温度调低更稳 temperature 0.2 [logging] level info # 出问题时打开能看到实际请求的 endpoint log_request true再看settings.json适合编辑器插件或 Agent 类工具{ taotoken: { baseUrl: https://taotoken.net/api, apiKey: sk-你的TaoTokenKey, defaultModel: claude-sonnet, models: { fast: gpt-4o-mini, strong: claude-sonnet }, request: { timeout: 60000, maxRetries: 3 }, features: { explainGitHookLog: true, generateCommitMessage: true } } }两份配置的核心就三点base_url 指向https://taotoken.net/apiapi_key 用你控制台建的那串模型名按需选。放好之后你的工具就会走这条统一通道而不是散落各处的旧 Key。配置完先别急着推代码用一条最小请求验证通道是否通。命令行里可以这样测curl -s https://taotoken.net/api/v1/models \ -H Authorization: Bearer sk-你的TaoTokenKey \ -H Content-Type: application/json | head -c 500返回里有模型列表说明 Key 和 base_url 都对。这一步过了再回到 Git 排查你就有个能随时问的模型助手了。4. 四条线逐条定位 pre-receive hook declined现在进入正题。按「服务端钩子 → 分支保护 → 权限 → 提交规范」顺序查基本能覆盖九成情况。4.1 服务端钩子本身在拦什么pre-receive 是服务端仓库hooks/目录下的脚本它在收到推送、还没更新 ref 之前执行。如果脚本exit 1Git 就返回 pre-receive hook declined。你要做的是看到脚本到底输出了什么。GitLab 用户看Settings - Repository - Protected Branches同时让管理员查/var/opt/gitlab/git-data/repositories/namespace/repo.git/custom_hooks/pre-receive或系统钩子目录。GitHub 没有自定义 pre-receive 给你改但它的分支保护、必需状态检查、签名要求都会以类似方式拒绝。Gitea/Gogs 看仓库hooks/pre-receive.d/。一个常见坑钩子里有while read oldrev newrev refname循环如果脚本对refname做了白名单而你推的是refs/heads/master不在白名单里就被拒。让管理员把钩子日志级别调高或者临时在脚本里加echo ref$refname输出你就能看到它卡在哪一行。4.2 分支保护master 是不是被锁了这是最高频原因。很多平台默认把 master/main 设为保护分支只允许 Maintainer 及以上直推Developer 必须走 Merge Request。你给用户 B 开了 Developer 权限但他依然推不了 master就是因为保护规则里Allowed to push没放开。以 GitLab 为例路径是Settings - Repository - Protected Branches - Expand把Allowed to push从Maintainers改成Developers Maintainers或者干脆允许特定人。改完再推。GitHub 在Settings - Branches - Branch protection rules检查Require a pull request before merging和Restrict who can push。提示生产仓库不建议直接放开 master 直推。更稳的做法是让 B 推到 feature 分支再开 MR。保护规则的本意就是防误推别为了省事把它拆了。4.3 权限与角色Developer 到底能干什么权限模型各平台不同但逻辑类似。GitLab 里 Guest 只能看Reporter 能看不能推Developer 能推非保护分支、能开 MRMaintainer 才能改保护规则和直推保护分支。所以你给 B 开 Developer他推 feature 分支没问题推 master 就会被 pre-receive 拦。验证方法让 B 执行git push origin HEAD:refs/heads/test-branch如果这个能成说明权限本身没问题问题在 master 的保护规则。如果连非保护分支都推不了那要查仓库成员角色、SSH key 是否绑对账号、以及是否有 IP 白名单。4.4 提交规范commit message 和文件大小有些团队的 pre-receive 钩子会校验 commit message 格式比如必须匹配^(feat|fix|docs|chore): .。你的 message 写成「update」就会被拒。还有钩子限制单文件大小比如超过 100MB 直接拒报错里通常带文件名。排查命令# 看最近几条 commit message 格式 git log --oneline -5 # 找出本次推送里的大文件 git diff --stat HEAD~1 HEAD | sort -k3 -n -r | head # 如果某个大文件是误提交从历史里移除 git rm --cached path/to/big.file git commit --amend -m chore: remove large file如果钩子要求 GPG 签名你还要git config commit.gpgsign true并配好 key。签名缺失也会以 pre-receive 拒绝的形式出现。5. 验证请求与成功结果长什么样排查完用一条干净的推送验证。假设你已放开保护或改推 feature 分支git checkout -b fix/pre-receive-check git add . git commit -m fix: verify push after hook adjustment git push origin fix/pre-receive-check成功时你会看到Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 320 bytes | 320.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) remote: remote: To create a merge request for fix/pre-receive-check, visit: remote: https://your-git-host/.../merge_requests/new?... remote: To https://your-git-host/group/repo.git * [new branch] fix/pre-receive-check - fix/pre-receive-check关键是没有remote rejected且最后一行是[new branch]或master - master。如果推的是 master 且保护已放开你会看到abc1234..def5678 master - master。同时验证 TaoToken 通道让模型读一段钩子日志确认它能正常返回。用模型对话入口 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 贴入报错问「这段 pre-receive 脚本在哪一行拒绝了 refs/heads/master」能给出定位就说明通道和配置都生效了。6. 本篇常见错排查清单报错依旧但日志为空钩子可能把 stderr 吞了。让管理员在 pre-receive 里加set -x或把输出重定向到文件再复现一次。改了保护规则还是被拒检查是否有多个保护规则叠加或者仓库继承了 group 级别的保护设置。GitLab 里 group 的 Protected Branches 会覆盖项目级。Developer 推 feature 也被拒查仓库是否设了push rules比如禁止未签名提交、禁止作者邮箱不匹配。这类规则在Settings - Repository - Push Rules。SSH 能连但 push 被拒ssh -T gityour-host确认身份是哪个账号。多 Key 场景下~/.ssh/config里 Host 别名可能指错账号。TaoToken 请求 401Key 复制时带了空格或 base_url 写成了带路径的https://taotoken.net/api/v1而工具又自动拼/v1。统一用https://taotoken.net/api让工具自己拼版本路径。模型返回超时config.toml 里timeout_seconds调大到 120max_retries保持 3。长日志分析容易超时可以先把日志截断到关键 200 行再喂。commit message 校验总不过用git commit --amend改最近一条历史多条用git rebase -i HEAD~n批量改。改完强推 feature 分支没问题master 上慎用--force。排查推送问题时把钩子日志、保护规则截图、git remote -v输出一起丢给模型比你自己逐行读脚本快得多。通道配好之后这类「读日志定位」的活基本可以交给它你专注改代码就行。