github-protocols不是开关,而是按顺序尝试的协议列表,默认["https","ssh"],优先https,失败后才fallback ssh;它仅在--prefer-source或无dist时生效,且受git的insteadof规则优先覆盖。

github-protocols 不是开关,而是一组按顺序尝试的协议列表。它决定 Composer 在克隆 GitHub 仓库时先试什么、再试什么,失败才 fallback —— 默认值 ["https", "ssh"] 表示优先 HTTPS,仅当 HTTPS 失败(如认证失败、网络拦截)时才尝试 SSH。
github-protocols 的实际匹配逻辑
Composer 并不“解析 URL 协议”,而是根据包元数据中声明的 GitHub 源(如 github.com:vendor/package),自动拼出对应协议格式的地址:
- HTTPS 模式 →
https://github.com/vendor/package.git - SSH 模式 →
git@github.com:vendor/package.git
它按 github-protocols 数组顺序依次尝试,只要某次 clone 成功就停止;不会并行或随机选。
常见错误现象:Cloning into ''... Permission denied (publickey),往往是因为你设了 ["ssh", "https"],但 SSH 密钥未加载或未添加到 agent,而 Composer 没 fallback 到 HTTPS(因为默认 fallback 是开启的,但某些旧版或自定义配置可能禁用)。
为什么只设 https 有时仍走 SSH?
这个行为通常不是 github-protocols 本身的问题,而是被 Git 的 URL 重写规则覆盖了:
- 如果执行过
git config --global url."git@github.com:".insteadOf "https://github.com/",Git 层会强制把所有https://github.com/...替换为 SSH 地址 - 此时即使
github-protocols设为https,Composer 调用git clone时传入的仍是 HTTPS 地址,但 Git 自动转成 SSH 执行 - 验证方式:进
vendor/xxx目录,运行git remote -v,看 fetch 地址是不是git@github.com:
所以,github-protocols 和 Git 的 insteadOf 规则可能共存,且后者优先级更高 —— 它发生在 Git 进程内部,Composer 完全感知不到。
如何确认当前生效的是哪条协议?
最可靠的方式不是看配置,而是观察真实执行过程:
- 加
-v参数运行composer install,搜索关键词:Cloning或Executing command.*git clone - 如果看到
Cloning git@github.com:...,说明走了 SSH - 如果看到
Downloading https://api.github.com/...,说明走的是 dist(与github-protocols无关) - 如果看到
Cloning https://github.com/...,说明github-protocols生效且没被 Git 重写覆盖
注意:--prefer-dist 下完全不触发 github-protocols,因为它根本不用 git clone;只有 --prefer-source 或包无 dist 信息时,该配置才起作用。
真正容易被忽略的一点:github-protocols 对私有仓库的 HTTPS 认证没有自动兜底能力。设成 https 后,若没在 auth.json 里配好 GitHub Token,Composer 会直接报 401,不会静默 fallback 到 SSH —— fallback 只发生在同一协议族内(比如 HTTPS 失败后试另一个 HTTPS 地址),跨协议 fallback 需要明确列出两种协议。











