☰
使用公司Git提交代码时报错 [remote rejected] main -> main (pre-receive hook declined) error:从 pre-receive hook 到
2026/10/7 14:20:59 网站建设 项目流程

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 Plan:https://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 status

git 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" PATTERN="PROJ-[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-fix

4.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 Unauthorized

remote: 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 failed

fatal: 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/api,Key 是否有效,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,通了再查规则,不通先修凭证。顺序对了,能省很多时间。

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

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

立即咨询