Community编程与开发github.com

GitHub 推送前预检

对仓库的 Git/GitHub 配置进行只读预检,尤其适用于首次推送前。报告推送时将使用哪个 GitHub 账户进行身份验证、提交的作者身份、远程 URL 是否被 insteadOf 重写,以及分支和远程状态是否允许推送。

GitHub 推送前预检 是什么?

GitHub preflight 技能是一个专注于开发者在首次或常规推送前诊断 Git 仓库配置的 AI 助手(适用于 Claude Code、Coder 等平台)。它通过运行只读脚本(如 `git config --get`、`ls-remote`、`ssh -T`、`push --dry-run`)来检测常见的失败模式,例如空目录/无提交导致 `src refspec <branch> does not match any`、分支名不匹配(master vs main)、远程 URL 被 `insteadOf` 静默重写、SSH 或 HTTPS 身份验证账户与预期不符、提交身份(user.email)与远程账户不匹配,以及远程状态拒绝非快进推送。该技能坚持“只诊断,不修改”的原则——它报告发现的问题并提供可复制的修复命令,让用户自己决定如何配置。它特别适合多 GitHub 账户或多 SSH 主机别名的场景,因为这种场景下推送可能以错误的身份静默成功。技能支持通过 `bash <skill-dir>/scripts/preflight.sh [repo-path] [remote-name]` 运行,也可以在脚本不可用时使用单行命令手动检查。最终报告以简短表格展示检查结果,并仅针对失败或警告项给出按执行顺序排列的修复命令。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jijojohny/claude-skills/tree/HEAD/github-preflight

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

GitHub 推送前预检 是做什么的?

推送新仓库失败的方式就那么几种无聊、重复的情况,而且错误信息往往指向错误的方向。src refspec main does not match any 听起来像分支问题,但通常意味着没有提交。一个在工作账户下静默成功的推送,看起来和正确成功的推送一模一样。本技能在用户浪费一次推送尝试之前,提前发现这些问题。

指导原则:诊断,不修改。 报告发现的问题,并提供可复制粘贴的修复命令。由用户自己运行。人们之所以保留多个账户,正是因为他们关心哪个账户在操作,所以悄悄地替他们运行 git config 或 git remote set-url 恰恰是错误的直觉。

运行方式

bash <skill-dir>/scripts/preflight.sh [repo-path] [remote-name]

两个参数都是可选的——默认使用当前目录和 origin。该脚本仅读取:git config --get、ls-remote、ssh -T、push --dry-run。它从不写入。

如果脚本因故无法运行,下面的检查每项都是一行命令;直接运行它们并采用相同的解释方式。

检查结果的含义

脚本打印 PASS / WARN / FAIL 行。解释比原始输出更重要,因此请翻译而非粘贴:

仓库 / 文件 / 提交。 空目录或无提交的仓库会在推送时产生 src refspec <branch> does not match any。Git 无法凭空构建提交。这是首次推送失败的最常见原因,因此一旦触发,请优先提及。

分支。 新 git init 可能停留在 master,而远程期望 main。重命名在首次提交之后是安全的(git branch -M main)——未出生分支上还没有任何可重命名的内容,因此命令顺序错误会浪费一个周期。

有效远程 URL。 值得精确了解,因为很容易错误检查:git remote get-url 已经展开了 url.<base>.insteadOf,git ls-remote --get-url 也是如此。因此比较这两者检测不出任何差异。原始值仅存于 git config --get remote.<name>.url 中,这就是脚本将其与 git remote get-url --push(--push 形式额外覆盖了 pushurl 和 pushInsteadOf,这正是推送实际使用的)进行比较的原因。当两者不同时,用户配置的 URL 并不是 Git 将要连接的 URL。经典的陷阱是全局的 url."https://github.com/".insteadOf = [email protected]:,它会将 SSH 静默重定向到 HTTPS,从而使用凭证管理器持有的任意账户——通常不是用户期望的那个。务必报告有效 URL,并明确标注差异。

身份验证账户。 对于 SSH,脚本通过 ssh -G 解析主机(因此像 github-personal 这样的主机别名会被跟踪到真实主机名和密钥),然后直接通过 ssh -T 询问 GitHub。GitHub 回复 Hi <username>! 并以 1 退出——这里的退出码 1 是成功情况,而非失败。对于 HTTPS,它读取当前 gh 账户。将该账户与 URL 的所有者部分进行比较:不匹配意味着推送将返回 403,或落入错误的命名空间。

提交身份。 从全局配置继承的 user.email 是静默失败。推送以一个账户进行身份验证,但每次提交的作者却是另一个地址——事后修复需要修改或重写历史。当仓库的远程属于不同所有者时,将全局作用域的身份视为 WARN 并重点提出,即使技术上尚未出现任何问题。

远程状态。 空的远程意味着首次推送是干净的。存在已有引用意味着普通推送将被拒绝(非快进),用户需要先 pull/rebase——在用户遇到拒绝之前就说明这一点。这里的错误通常意味着仓库不存在或账户缺少访问权限;GitHub 故意将两者都报告为“未找到”,因此提供两种解释而不是猜测。

试推送。 仅在存在提交后可能。这是真正的端到端检查——它演练身份验证和引用协商,但不写入。注意其盲点:它不会捕获服务器端拒绝,如 GH007(邮箱隐私),因为这些是在实际接收时评估的。

报告

给出一个简短的检查表格,然后——仅针对失败或警告的项目——给出可运行的精确修复命令,按执行顺序排列。不要将通过的检查表述为散文;用户想知道什么出错了以及要输入什么。

当需要设置身份时,优先使用仓库本地配置而非全局配置,因为关键点在于此仓库与机器的默认配置不同:

git config user.name  "<account>"
git config user.email "<email>"

如果多个仓库需要同样的处理,提到 includeIf 作为持久解决方案:

[includeIf "gitdir:~/personal/"]
    path = ~/.gitconfig-personal

如果推送被 GH007 拒绝,请指向 GitHub → 设置 → 邮箱中的 @users.noreply.github.com 地址,而不是猜测个人地址——关键评论和本地配置是标签,不是账户接受的证明。

相关技能