path仓库在CI中根本不会生效,因Composer源码层面对type: "path"仓库硬性屏蔽,不报错、不提示,直接静默忽略;本地开发可用,但CI必须改用vcs、私有Packagist或package类型仓库。

path仓库在CI里根本不会生效
CI 环境默认不支持 type: "path" 仓库,不是配置错,是设计上就禁用。Composer 在非交互、无用户上下文的 CI 场景中会直接跳过所有 path 类型仓库——连报错都不会有,静默忽略。
常见现象:composer install 成功但 vendor 里没你的本地包,composer show --all | grep your/package 完全查不到。这不是缓存或权限问题,是 Composer 源码层面对 path 的硬性屏蔽。
- GitLab CI、GitHub Actions、Jenkins 等全部适用该规则
- 即使你加了
"symlink": false或把路径写成绝对路径,也无效 -
composer diagnose不会提示 path 被忽略,得靠composer show --all对比确认
为什么本地能跑,CI 就挂?路径解析逻辑完全不同
本地开发时,Composer 把 url 当作相对于当前项目 composer.json 的路径;而 CI 流水线拉取的是 clean checkout,工作目录里根本不存在你写的 ../my-package 这种上级目录。
更隐蔽的问题是:某些 CI 镜像(如 php:8.2-cli)默认没挂载宿主机路径,../ 指向的是空目录或不存在的层级,Source path does not exist 错误反而不出现——因为 Composer 根本没走到校验那步,提前跳过了整个仓库。
- Windows CI(如 GitHub Actions on windows-latest)还会因符号链接权限缺失 fallback 到 copy,但前提是它先认出这个仓库
- Docker 构建中若用
COPY . /app,../指向的是镜像根目录外,必然失败 - 唯一“可能”成功的场景是 monorepo + 自定义构建脚本提前
git clone到指定位置,但这已脱离标准path语义
CI 中替代 path 仓库的三种可行方案
别挣扎适配 path,改用 Composer 原生支持的、CI 友好的方式:
- 私有 Packagist(如 Satis、Private Packagist、GitLab Package Registry):把本地包打 tag 后发布,CI 用标准
vcs或composer类型仓库拉取 - Git URL 直接引用开发分支:
"url": "https://gitlab.example.com/myorg/my-pkg.git",require 写"dev-main as 1.0.x-dev",配合--prefer-dist加速 - 临时打包成 tarball 并托管 HTTP:生成
my-pkg-1.0.0.tar.gz放到 CI 可访问的内网地址,repositories 设为{"type": "package", "package": {...}},手动声明 dist.url
注意:所有方案都要求 composer.lock 提交,且 CI 必须用 composer install --no-dev --optimize-autoloader --classmap-authoritative,否则 autoload 性能崩塌或类找不到。
最易被忽略的陷阱:开发机和 CI 的 autoload 行为不一致
就算你用上述方案让包进了 vendor/,如果本地开发依赖 path 仓库的 symlink 机制,而 CI 用的是 dist 安装,autoload 映射生成逻辑就不同。
例如:本地改了 src/Helper.php,IDE 立刻生效;CI 构建后却还用着旧 classmap,因为 --classmap-authoritative 把旧映射锁死了,而 composer dump-autoload -o 又没在 CI 里执行(也不该执行)。
结论:不要让开发流程和 CI 流程依赖同一套仓库类型。path 仅限本地快速验证,上线路径必须收敛到 VCS 或私有源——否则每次发版都在赌 autoload 是否同步。


















