1. 先别急着改代码,这个报错根本不是网络问题
git push到 master 时看到! [remote rejected] master -> master (pre-receive hook declined),第一反应往往是「是不是网断了」「是不是凭证过期了」。我一开始也这么想,结果折腾半天发现方向完全错了。
这个报错的意思是:你的推送请求已经成功到达远端服务器,但服务器在真正写入仓库之前,运行了一个叫pre-receive的钩子脚本,这个脚本拒绝了你的提交。换句话说,网络是通的,认证也过了,卡在的是「服务端规则校验」这一层。
它和Permission denied (publickey)、Could not resolve host这类错误有本质区别。后面那些是链路没打通,而pre-receive hook declined是链路通了、服务端说「你这个推送我不接受」。
典型触发场景有这么几类:你用的账号不是项目归属者或没有写权限;master 分支被保护了,不允许直接 push;提交里带了服务端钩子校验不通过的内容(比如大文件、提交信息格式、签名要求);或者你本地配置的 remote 指向了一个你根本没权限的仓库地址。
这篇就围绕「推送链路」这个思路,从远端钩子校验、分支保护、凭证与代理三层来定位,同时给出用 TaoToken 统一 Key 管理凭证的配置骨架,让你在多个仓库、多个账号之间切换时不再混乱。适合刚接触 GitLab/GitHub 私有仓库、被这个报错卡住的开发者。
2. 为什么用 TaoToken 统一 Key 来排查推送链路
排查这个问题的难点不在于命令本身,而在于凭证来源太多、太乱。你可能本地有 SSH key、有 credential helper 缓存的账号密码、有环境变量里的 token、还有 IDE 里单独配置的一套。当推送被拒时,你根本不知道当前这次 push 到底用的是哪个身份。
TaoToken 在这里的作用不是「绕过权限」,而是把访问凭证收敛成一套统一 Key,让你能明确知道「我现在用哪个身份在推」。它的 API 地址是https://taotoken.net/api,官网在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。你可以把它理解成一个统一的凭证与模型接入管理入口,配合settings.json骨架,把 remote、credential、以及后续的模型调用配置集中管理。
需要说清楚的是:TaoToken 解决的是「凭证统一与链路可观测」,它不能替你绕过服务端的分支保护或权限校验。如果远端钩子明确拒绝,你还是得去服务端改规则或换有权限的账号。但有了统一 Key,你至少能快速确认「我用的身份对不对」,把排查范围从「玄学」缩小到「具体哪一层」。
对于长期做编码、跑 Agent 任务的场景,统一 Key 的价值更明显——你不用在多个项目间反复切换凭证,一套配置走到底。如果你后续要接 Coding Plan 做长期编码任务,这个统一入口会更省心。
3. 可复制的配置:remote、credential 与 settings.json 骨架
先把当前状态摸清楚。执行下面这几条,看看你的 remote 到底指向哪、用的什么协议:
git remote -v git config --list --show-origin | grep -i -E "credential|remote|user" git branch -vvgit remote -v会告诉你推送地址是 HTTPS 还是 SSH。如果是 HTTPS,凭证走的是 credential helper;如果是 SSH,走的是~/.ssh/config和 key。这一步能帮你确认「我到底在往哪推」。
接着统一凭证配置。如果你用 HTTPS,建议显式配置 credential helper,避免系统缓存了旧账号:
# 清除旧的缓存凭证(谨慎,会清掉当前仓库的缓存) git config --global --unset credential.helper git config --global credential.helper store # 确认 remote 地址 git remote set-url origin https://<你的仓库地址>.git然后是settings.json骨架,把统一 Key 和接入配置集中管理。这个文件可以放在你的项目根目录或用户配置目录下:
{ "git": { "remote": "origin", "defaultBranch": "master", "credentialHelper": "store" }, "taotoken": { "apiBase": "https://taotoken.net/api", "apiKey": "<你的统一Key>", "model": "claude-code", "timeout": 30000 }, "push": { "verifyRemote": true, "checkBranchProtection": true } }这个骨架的核心思路是:把「用哪个 Key」「推哪个 remote」「默认分支是什么」都写在一处,排查时一眼能看全。apiKey建议通过环境变量注入,不要硬编码进版本库:
export TAOTOKEN_API_KEY="<你的统一Key>"然后在settings.json里引用环境变量,或者在你的 credential 配置里用这个 Key 作为 HTTPS 密码。这样每次 push 时,用的都是同一套身份,不会再出现「这次推用的是哪个账号」的困惑。
如果你需要生成或管理这个统一 Key,可以到 API Keys 页面操作:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite。接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite,里面有完整的参数说明。
4. 逐步验证:从本地到远端,一层层确认推送成功
配置改完,别急着直接 push 到 master。按下面顺序逐层验证,每步都能定位到具体哪一层出问题。
第一步,确认本地提交没问题:
git status git log --oneline -5确保没有未提交的改动,且最近的提交是你想推的。
第二步,确认 remote 地址和分支对应关系:
git remote show origin这条会显示远端的分支、跟踪关系、以及 push 的默认目标。如果显示master被保护,这里通常会有提示。
第三步,先推到一个临时分支,绕开 master 的保护规则,验证凭证和链路是否通:
git checkout -b test-push-check git push origin test-push-check如果这个能成功,说明凭证、网络、权限都没问题,问题就锁定在 master 的分支保护或 pre-receive 钩子上。如果这个也失败,那问题在凭证或权限层。
第四步,如果临时分支能推,回到 master 场景,检查服务端分支保护设置。以 GitLab 为例,进入项目 Settings → Repository → Protected Branches,看 master 是否被设为「不允许直接 push」。GitHub 则在 Settings → Branches 里看 branch protection rules。
第五步,确认你的账号在项目里的角色。GitLab 里至少要是 Developer 及以上才能 push 到非保护分支,Maintainer 才能推保护分支。用项目归属账号或有权限的账号重新配置凭证:
git config --global user.name "<有权限的账号名>" git config --global user.email "<对应邮箱>"第六步,重新 push:
git push origin master如果还是pre-receive hook declined,那就不是权限问题,而是服务端钩子脚本本身在拒绝。这时候需要联系仓库管理员看钩子日志,或者检查提交里是否有触发规则的内容(比如提交信息格式、文件大小、签名要求)。
成功的结果应该是类似这样的输出:
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) To https://your-repo.git a1b2c3d..e4f5g6h master -> master看到master -> master且没有 rejected 字样,就说明推送成功了。
5. 本篇常见错排查:这几个坑我踩过
坑一:以为改了 remote 就换了身份。实际上 credential helper 缓存的是旧账号,git remote set-url只改地址不改凭证。必须清缓存或重新输入。执行git config --global --unset credential.helper后再 push,会重新提示输入账号密码。
坑二:SSH 和 HTTPS 混用。你本地配了 SSH key,但 remote 是 HTTPS,那 SSH key 根本用不上。用git remote -v确认协议,两者要匹配。如果要用 SSH,remote 应该是git@host:user/repo.git格式。
坑三:master 分支保护规则没看。很多人直接 push master 被拒,以为是权限问题,其实是分支保护。GitLab 默认可能对 master 开了保护,需要 Maintainer 权限或走 Merge Request。临时验证可以推到新分支再提 MR。
坑四:pre-receive 钩子校验提交内容。有些服务端钩子会检查提交信息是否符合规范、是否带签名、文件是否超限。这种拒绝和权限无关,得看钩子脚本的具体规则。可以试着用一个最简单的提交测试:
git commit --allow-empty -m "test: verify push chain" git push origin master如果空提交也被拒,那基本就是分支保护或账号权限;如果空提交能过、正常提交被拒,那就是钩子在检查内容。
坑五:统一 Key 配置了但没生效。检查settings.json里的apiKey是否被环境变量覆盖,或者 credential store 里是否还存着旧密码。可以删掉~/.git-credentials文件重新来一遍。
如果你在验证模型或调试接入配置时需要快速测试,可以用模型对话页面:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite,确认 Key 和链路是否正常。控制台在https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite,可以看调用记录和状态。
6. 把推送链路固定下来,下次不再靠猜
排查完这一轮,建议把配置固化,避免下次再遇到类似问题时重新猜。核心就三件事:remote 地址写清楚、凭证统一到一套 Key、分支保护规则提前确认。
如果你长期做编码任务、跑 Agent 流程,建议直接上 Coding Plan,把统一 Key 和模型接入配置一次配好,后续多个项目复用:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite。Claude Code 相关的接入配置在https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite,里面有 settings.json 的完整字段说明。
最后留一个实用习惯:每次换项目或换账号时,先跑一遍git remote -v和git config --list | grep credential,确认当前身份和地址。这个动作花不了十秒,但能省掉大量「为什么推不上去」的排查时间。推送链路清晰了,pre-receive hook declined这类报错就只是一个明确的信号,而不是一团迷雾。