子项目需隔离 vendor 目录、显式配置 autoload、独立 .gitignore 和 ci 工作目录,避免与主项目冲突。具体包括:子项目 composer install 加 --no-autoloader --no-scripts;vendor-dir 设为唯一路径;autoload 用 psr-4 显式声明不重叠命名空间;子项目根目录放 /vendor 到 .gitignore 并 git add -f;ci 中 cd 进子项目再执行 composer install。

subtree 项目里直接 composer install 会污染主项目 vendor
子树合并后,子项目的 composer.json 和 vendor/ 如果和主项目共存,Composer 默认会把所有依赖装进主项目的 vendor/,导致冲突、版本错乱、自动加载失败。根本原因是 Composer 没有“作用域”概念,它只认当前目录或向上最近的 composer.json。
实操上必须切断子项目对主项目 vendor/ 的感知:
- 在子项目目录下执行
composer install --no-autoloader --no-scripts,避免触发主项目的 autoloader 注册逻辑 - 手动设置子项目的
vendor-dir:在子项目composer.json的"config"段加"vendor-dir": "lib/my-subtree/vendor"(路径需唯一且不与主项目重叠) - 子项目
autoload必须用"psr-4"或"classmap"显式声明命名空间前缀,不能依赖主项目的自动发现 - 主项目
autoload-dev或autoload里不要包含子项目源码路径,否则 Composer dump-autoload 会把子项目类也扫进去
子项目 vendor 如何不被 git subtree push 带走
Git subtree 的 push 默认递归提交整个子目录,如果子项目 vendor/ 在其目录内,就会被一起推到上游仓库——这不仅增大历史体积,更违反“vendor 不进 Git”的原则。
关键动作是让子项目目录本身忽略 vendor/,但又不影响主项目其他部分:
- 在子项目根目录(即 subtree 目录)下放一个
.gitignore,内容只有/vendor(开头加/确保只匹配本级) - 确认该
.gitignore已被 git 跟踪:git add -f path/to/subtree/.gitignore - 执行
git subtree push前,先运行git clean -xffd path/to/subtree/vendor清掉残留(尤其 CI 环境容易卡着旧 vendor) - 不要在主项目根目录的
.gitignore里写子项目vendor路径——它对 subtree 子目录无效
子项目 autoload 怎么和主项目互不干扰
最常出问题的是 composer dump-autoload 后,主项目能 new 出子项目的类,但子项目自己的测试脚本却报 Class not found——说明 autoloader 加载链错位了。
根本解法是物理隔离 + 显式加载:
- 子项目
composer.json中"autoload"的"psr-4"键值对,命名空间前缀必须和主项目不重叠,例如用"MySubtree\": "src/",而非"App\" - 子项目内运行脚本时,必须 require 自己的
vendor/autoload.php,比如require __DIR__.'/lib/my-subtree/vendor/autoload.php'; - 主项目若要使用子项目类,不能靠 Composer 自动发现,而应通过
composer config repositories把子项目当私有包引用,或用path类型 repo +composer require - 避免在子项目中调用
ClassLoader::addPsr4()手动注册——这会让加载器状态变得不可控
CI 环境下 subtree vendor 构建失败的典型原因
本地好好的,CI 上 composer install 却提示 Could not find a composer.json file 或 Package x is not installed,往往是因为工作目录或上下文切换错了。
检查点非常具体:
- CI 脚本中进入子项目目录后,必须用
cd path/to/subtree && composer install,不能只写composer install --working-dir=path/to/subtree(某些旧版 Composer 不支持该参数) - 确认 CI 使用的 Composer 版本 ≥ 2.2,低版本对嵌套
vendor-dir支持不稳 - 子项目
composer.json中不要出现"repositories"指向主项目私有源——CI 没权限访问,应统一用环境变量或auth.json配置 - 如果子项目依赖了主项目中的 dev 包(如
"my-org/core": "dev-main"),CI 必须先composer install主项目,再用--repository-url=file://$(pwd)让子项目能读到本地包
嵌套 vendor 的本质不是功能需求,而是边界控制需求。一旦漏掉任意一个隔离点——路径、autoload、git ignore、CI 工作目录——就可能在某个环节突然崩掉,而且错误信号分散,不容易一眼定位。










