![使用公司Git提交代码时报错 [remote rejected] main -> main (pre-receive hook declined) error:从 pre-receive hook 到](http://pic.xiahunao.cn/yaotu/使用公司Git提交代码时报错 [remote rejected] main -> main (pre-receive hook declined) error:从 pre-receive hook 到)
1. 公司内网推送被拒先搞清楚 pre-receive hook 到底拦了什么remote rejected main - main (pre-receive hook declined)这个报错本质上是服务端在收到你的推送包之后、真正写入仓库之前执行了一段叫pre-receive的脚本脚本返回了非零退出码于是整批推送被整体拒绝。它和认证失败、网络超时是两码事认证失败通常报Authentication failed或403网络问题报Could not resolve host而pre-receive hook declined说明你的身份已经通过代码也传到了服务端是服务端的规则不让你合入。这个钩子能做什么几乎什么都能做。公司内网 Git 服务GitLab、Gitea、Bitbucket 自建、Gerrit 等常挂的检查包括分支保护、提交信息格式比如必须带 Jira 单号、禁止大文件、禁止直接推 main、代码签名验证、CI 预检查、目录白名单。所以同一个报错背后可能是权限问题也可能是你 commit message 少了个PROJ-123。适合谁看刚进公司、第一次往内网仓库推代码被拦住的开发者或者老手换了仓库、规则变了一时摸不着头脑。下面我会按「先本地复现 → 再逐层定位 → 最后对照规则修」的顺序把可复制的命令和排查路径给全。核心检索词就是 pre-receive hook declined 的定位方法你跟着敲一遍基本能锁定是哪一类规则在拦你。先建立一个认知这个错误信息本身不告诉你具体原因服务端出于安全考虑通常只回一句pre-receive hook declined真正的拒绝理由写在服务端日志或返回给你的 stderr 里。所以排查的关键是「让服务端把话说清楚」或者「用本地手段逼近真相」。2. 动手前的前置准备确认远端、凭证与 TaoToken 接入位在逐层排查之前先把环境摸清楚避免把「凭证过期」误判成「钩子拒绝」。第一步永远是看远端配置git remote -v输出会告诉你推送地址是http://还是ssh://。内网常见的是 HTTP(S)比如http://git.inspur.com/xxx-service.git。如果是 HTTP凭证走的是用户名 个人访问令牌PAT不是登录密码。很多公司平台在「用户设置 → Access Tokens」里生成 token本地git push弹窗时 password 填 token。token 过期或权限范围scope不含write_repository也会表现为推送失败但报错文案不同注意区分。如果你在本地做 AI 辅助编码比如用 Claude Code、Cline 这类工具生成提交信息或做代码审查需要模型服务时可以走 TaoToken 的接入方式。它的 API 地址是https://taotoken.net/api控制台在https://taotoken.net/console密钥在https://taotoken.net/api-keys生成。模型对话入口是https://taotoken.net/models长期编码或 Agent 场景可以看 Coding Planhttps://taotoken.net/coding-plan。文档在https://taotoken.net/doc。这些和 Git 推送本身是两条线但如果你用 AI 工具自动生成 commit message格式规范这一关就靠它帮你对齐。确认凭证有效性的最快方式是不推送、只读远端git ls-remote http://git.inspur.com/xxx-service.git能列出 refs说明认证和网络都通问题就锁定在「写操作被规则拦」。如果这一步就失败先解决凭证别往下查钩子。另外确认本地分支和远端分支的对应关系git branch -vv git statusgit status会告诉你有没有未跟踪文件、是否有未推送的 commit。未跟踪文件本身不会导致 pre-receive 拒绝它拦的是你推上去的 commit但如果你git add .把不该提交的文件带进去了可能触发「禁止某些文件类型」的钩子。所以推送前先看清暂存区。3. 可复制配置分支保护、提交规范与钩子日志核对清单这一节是核心给你能直接抄的配置片段和核对清单。先说要改的本地配置再说服务端规则怎么核对。3.1 本地 Git 配置片段.git/config视角推送被拒时先确认推送目标不是被保护分支。查看当前分支git rev-parse --abbrev-ref HEAD如果输出是main或master而公司规则禁止直接推主干你需要新建特性分支git checkout -b feature/PROJ-123-fix-push git push -u origin feature/PROJ-123-fix-push-u会把本地分支和远端分支建立跟踪关系后续直接git push即可。这一步能绕开「禁止直推 main」这类最常见的拦截。3.2 提交信息规范配置很多公司的 pre-receive 钩子会校验 commit message 是否匹配正则比如必须包含PROJ-\d。你可以用本地钩子提前拦截避免推到服务端才被拒。在.git/hooks/commit-msg写入#!/bin/sh # .git/hooks/commit-msg MSG_FILE$1 PATTERNPROJ-[0-9]\ if ! grep -qE $PATTERN $MSG_FILE; then echo 提交信息必须包含 Jira 单号例如 PROJ-123 exit 1 fi赋权后生效chmod x .git/hooks/commit-msg这样 commit 阶段就会拦你比推到服务端再被拒省事得多。注意本地钩子不会自动同步给同事团队可以把它放进仓库的scripts/目录统一安装。3.3 服务端分支保护规则核对清单你未必有服务端权限但可以按这份清单去问管理员或自己在平台页面核对核对项常见取值影响保护分支main / master / release/*禁止直接 push只能走 MR允许推送角色Maintainer / Developer权限不足直接拒提交信息正则PROJ-\d格式不符拒文件大小上限5MB / 10MB超限拒禁止文件类型.exe.jar.zip命中拒强制代码签名GPG / SSH 签名未签名拒CI 预检查lint / test失败拒3.4 查看服务端钩子日志如果你有服务器访问权限钩子日志通常在仓库的hooks/目录或系统日志里。GitLab 的 pre-receive 日志在/var/log/gitlab/gitlab-shell/或gitaly日志中自建 Gitea 在log/目录。典型查看方式# 以 GitLab 为例查看最近的推送拒绝记录 sudo grep -i pre-receive /var/log/gitlab/gitlab-shell/gitlab-shell.log | tail -50日志里会写明具体拒绝原因比如Commit message does not match pattern或Branch main is protected。拿到这句话问题就定性了。3.5 用 AI 工具辅助生成合规提交信息如果你用 Claude Code 或 Cline 做提交可以在项目里放一份settings.json或.clinerules让模型按公司规范生成 message。以 Cline 的 MCP 配置为例接入模型服务时填三件套{ mcpServers: { taotoken: { command: npx, args: [-y, taotoken/mcp-server], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: 你的Key, TAOTOKEN_MODEL_ID: claude-sonnet-4-5 } } } }Base URL、Key、Model ID 三件套缺一不可路径要和文档一致。这样生成的 commit message 更容易过正则校验。Claude Code 的接入文档在https://taotoken.net/doc按里面的步骤配ANTHROPIC_BASE_URL即可。4. 验证请求从本地复现到推送成功的完整链路排查完规则要验证你的修改是否真的解决了问题。按下面链路走一遍。4.1 本地复现拒绝先确认当前状态能复现报错git push origin main如果输出remote rejected main - main (pre-receive hook declined)说明问题稳定存在便于对照修复。4.2 切换到合规分支并推送git checkout -b feature/PROJ-123-fix git add . git commit -m PROJ-123 修复推送被拒问题 git push -u origin feature/PROJ-123-fix如果这次成功说明之前是「直推保护分支」被拦。输出里会看到remote: Creating merge request之类的提示或者直接显示新分支创建成功。4.3 验证提交信息是否过钩子如果新分支也被拒重点查 commit message。用git log --oneline -5看最近提交确认格式。可以临时改一条git commit --amend -m PROJ-123 修正提交信息格式 git push -u origin feature/PROJ-123-fix4.4 验证文件大小与类型如果报错提到文件检查大文件git rev-list --objects --all | git cat-file --batch-check%(objecttype) %(objectname) %(objectsize) %(rest) | awk /^blob/ {print $3, $4} | sort -nr | head -10这条命令列出仓库里最大的 10 个对象单位是字节。超过公司上限的文件需要从历史里移除或者用 Git LFS 管理。4.5 用 ls-remote 确认远端可达推送前再跑一次git ls-remote origin能列出 refs 说明链路正常。如果这一步失败先解决网络或凭证别怀疑钩子。4.6 成功结果长什么样一次成功的推送会输出类似Enumerating objects: 12, done. Counting objects: 100% (12/12), done. Writing objects: 100% (7/7), 1.2 KiB | 1.2 MiB/s, done. To http://git.inspur.com/xxx-service.git * [new branch] feature/PROJ-123-fix - feature/PROJ-123-fix branch feature/PROJ-123-fix set up to track origin/feature/PROJ-123-fix.看到[new branch]或main - main且没有rejected就说明钩子放行了。接下来去平台提 MR走审核合并。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth推送被拒的排查路上你会撞到几个高频报错它们和 pre-receive 不是一回事但经常混在一起。逐个对照。5.1 401 Unauthorizedremote: HTTP Basic: Access denied fatal: Authentication failed for http://git.inspur.com/xxx-service.git/这是凭证问题不是钩子。原因通常是 PAT 过期、scope 不含write_repository、或者你用了登录密码而非 token。解决去平台「用户设置 → Access Tokens」重新生成scope 勾选write_repository本地清除旧凭证git config --global --unset credential.helper git config --global credential.helper store下次推送重新输入用户名 新 token。5.2 local proxy failedfatal: unable to access http://git.inspur.com/xxx-service.git/: Failed to connect to 127.0.0.1 port 7890这是本地代理配置残留。检查git config --global --get http.proxy git config --global --get https.proxy如果有输出清掉git config --global --unset http.proxy git config --global --unset https.proxy内网仓库通常直连不需要代理。清掉后重试git ls-remote。5.3 reading choices / 模型返回异常如果你在用 AI 工具生成提交信息时看到error reading choices或类似模型响应解析失败多半是 Base URL 或 Model ID 配错。核对三件套Base URL 是否为https://taotoken.net/apiKey 是否有效Model ID 是否在文档支持列表里。Cline 的 MCP 配置里TAOTOKEN_MODEL_ID要和实际模型名一致写错会返回空 choices。5.4 OAuth 相关报错remote: OAuth token expired部分平台用 OAuth 而非 PAT。解决重新走一遍平台的授权流程或者在凭证管理里刷新 token。如果是 Claude Code 接入场景报 OAuth 错误检查ANTHROPIC_BASE_URL是否指向https://taotoken.net/api以及 API Key 是否放在正确的环境变量里。5.5 钩子拒绝但日志无输出有时候服务端只回pre-receive hook declined日志里也没细节。这时用二分法把这次推送拆成多个小 commit逐个推看哪个被拒。或者临时把 commit message 改成最简格式排除格式问题。还可以联系仓库管理员让他们在服务端加一行echo输出拒绝原因方便定位。5.6 权限不足但报错像钩子有些平台权限不足时也回pre-receive hook declined。核对你在该仓库的角色Developer 通常不能直推保护分支Maintainer 可以。如果角色不够走 MR 流程或者找管理员提权。6. 语义一致收尾把排查路径固化成团队习惯排查完这一轮你会发现pre-receive hook declined本身不可怕可怕的是它不说原因。所以最实用的做法是把「本地预检」做在推送之前装好commit-msg钩子校验格式推送前跑git ls-remote确认链路用特性分支代替直推主干。这三步能挡掉八成拒绝。如果团队用 AI 辅助编码把提交规范写进 Cline 的 rules 或 Claude Code 的项目配置里让模型生成的 message 直接合规。需要模型服务时API 走https://taotoken.net/api密钥在https://taotoken.net/api-keys管理接入文档看https://taotoken.net/doc长期编码场景可以了解https://taotoken.net/coding-plan。模型对话验证在https://taotoken.net/models。最后留一个我踩过的坑有次推送被拒查了半天钩子结果是 PAT 的 scope 少了write_repository报错却显示成钩子拒绝。所以遇到这个错先跑git ls-remote通了再查规则不通先修凭证。顺序对了能省很多时间。