Composer path仓库必须用相对路径(如"packages/mylib"),禁用绝对路径;symlink需在被引用包composer.json中声明;require版本须严格匹配本地包name和version;必须提交composer.lock且禁止提交vendor/。

团队协作中直接用 path 仓库引用本地包,不加约束等于埋雷——路径硬编码、软链接失效、CI 构建失败、成员环境不一致,全都会在某次 composer install 后集中爆发。
path 仓库配置必须用相对路径,不能写绝对路径
绝对路径(如 /Users/alex/workspace/mylib 或 C:\dev\mylib)在他人机器上必然失效。Composer 的 repositories.type: "path" 只接受相对于项目根目录的路径。
- ✅ 正确:
"url": "packages/mylib"(假设目录结构是project/packages/mylib/composer.json) - ❌ 错误:
"url": "/home/alex/mylib"或"url": "../mylib"(上层目录超出项目边界,Composer 会跳过该仓库) - ⚠️ 注意:
url值不能以./开头,也不支持环境变量插值(${HOME}或$_ENV都不生效)
启用 symlink 必须在被引用包的 composer.json 中声明
很多人以为在主项目的 repositories 里加个 "options": {"symlink": true} 就能软链,其实没用——这个配置只对 vcs 类型仓库有效,path 类型的 symlink 控制权在「被引用包」自己手上。
- 必须在
packages/mylib/composer.json里写:"options": {"symlink": true} - 且该配置仅在执行
composer update mylib/package-name或composer update时生效;composer install不会重建软链接 - CI 环境通常禁用 symlink(如 Docker 容器挂载限制),此时应确保包本身有完整
autoload和可运行测试,避免依赖“实时编辑”
require 版本号必须匹配被引用包的 name + version
path 仓库不是“免版本校验通道”,它仍走完整依赖解析流程。如果被引用包的 composer.json 写着 "name": "acme/utils" 但 "version": "dev-main",而主项目 require 里写的是 "acme/utils": "^1.0",就会报错 Could not find package acme/utils。
- 最稳做法:被引用包用
"version": "dev-master"或"dev-develop",主项目对应写"acme/utils": "dev-master" - 更推荐:用
"version": "1.0.x-dev",主项目写"acme/utils": "1.0.x-dev",语义清晰且兼容性检查正常 - 切勿省略
version字段——Composer 2.5+ 会直接拒绝加载无 version 的 path 包
团队必须统一提交 composer.lock,且禁止 commit vendor/ 目录
有人觉得 “path 包是本地的,lock 文件无所谓”,这是最大误区。即使所有依赖都是 path 类型,composer.lock 仍记录了每个包的完整元信息、源类型、路径、哈希和 autoload 映射。缺失 lock 文件,不同人执行 composer install 可能加载不同版本的子依赖(比如某个 path 包依赖的 psr/log 被解析出两个不同 patch 版本)。
- 必须把
composer.lock提交进 Git,且每次修改任何repositories或require后都重新生成 -
vendor/永远不进 Git——它只是产物,不是源码;CI 流程必须走composer install --no-interaction - 建议在
.gitattributes中加composer.lock merge=union,避免多人同时更新依赖时 lock 文件冲突无法自动合并
真正难的不是配通 path,而是让所有人理解:path 仓库不是开发捷径,它是把本地包当作「已发布包」来对待的协作契约——name、version、autoload、锁文件,一个都不能少,否则就是把模块耦合悄悄转嫁成了配置耦合。


















