答案是:repositories必须写在项目根目录composer.json顶层,因Composer仅读取该位置的repositories数组;url需为相对路径,本地包name须与require完全一致,且需删除composer.lock和vendor后执行install才能生效。

type: "path" 是 Composer 唯一支持的本地文件系统包源方式,其他写法(比如直接 require 一个本地 ZIP 或用 file:// URL)都会失败或被忽略。
为什么 repositories 必须写在项目根目录 composer.json 顶层
Composer 只读取当前项目根目录下 composer.json 文件最外层的 repositories 数组。它不会递归查找子目录、不读取依赖包自己的 composer.json、也不认全局配置或 config 字段里的同名字段。
常见错误包括:
- 把
repositories塞进extra或config里 - 误以为在本地包自己的
composer.json中加repositories就能让主项目发现它 - 在子模块或 workspace 下错放路径,导致相对路径解析失败
验证是否生效:运行 composer config repositories,输出里必须出现你配置的 path 条目,且 url 是相对路径(如 ../mylib),不能以 / 开头。
url 和本地包 name 必须严格匹配
Composer 不会模糊匹配,也不会提示“名字接近但不一致”。只要有一个字符不同(大小写、中划线/下划线、vendor 名拼写),它就静默跳过该路径,转而尝试从 Packagist 下载——此时你会看到 Could not find package,但根本原因不是网络问题,而是匹配失败。
检查要点:
-
url必须是相对路径,例如../mylib或./packages/utils;Windows 上可写C:/dev/mylib,但避免 UNC 路径 - 目标目录下必须存在合法
composer.json,且其中"name"字段值(如"acme/utils")要和require中声明的完全一致 - 本地包的
composer.json中建议设"minimum-stability": "dev"和"prefer-stable": false,否则稳定性约束可能让dev-main这类分支别名被过滤
已有 composer.lock 时,path 仓库不会自动生效
Composer 安装行为分两种:install 读锁文件还原,update 重新解析 composer.json 并更新锁。一旦 composer.lock 存在,install 就完全忽略 repositories 配置变更——哪怕你刚加了 path,它仍照着旧锁去 Packagist 下载。
强制切换到本地路径的唯一可靠方式是:
- 删掉
composer.lock - 删掉
vendor/目录(残留的旧包会导致 autoload 错乱) - 运行
composer install(不是update)——它会重新读取composer.json,识别path仓库,并生成新锁文件
如果只想重装单个包,可用 composer remove acme/utils && composer require acme/utils:dev-main,但前提是 repositories 已正确配置并生效。
改了本地代码却没生效?检查符号链接状态
Composer 对 type: "path" 的处理默认是创建符号链接(Linux/macOS)或目录交接(Windows),而不是复制文件。这意味着修改本地源码本应立刻反映到主项目中。
但实际失效常因:
-
vendor/acme/utils是真实目录而非链接 → 上次install没走path流程,说明配置未生效或被跳过 - Windows 下未启用开发者模式或未以管理员权限运行命令,导致链接创建失败,退化为复制行为
- 没配
"options": {"symlink": true},某些 Composer 版本在非 Linux 环境下默认不 symlink
确认链接是否建立:在终端执行 ls -la vendor/acme/utils(Linux/macOS)或 dir vendor\acme\utils(Windows),看是否指向外部路径。不是链接,就得回溯前面三步——配置位置、命名匹配、锁文件清理,这三处任一出错都会导致 fallback 到复制模式,后续修改自然无效。











