composer global require不能替代本地包链接,因其仅安装到全局~/.composer/vendor/,不影响项目依赖;真正有效的是repositories中配置type: "path",需本地包含合法composer.json(含name字段),主项目配置相对或绝对路径并require对应dev-分支版本,安装后生成符号链接实现修改即生效。

composer global require 为什么不能替代本地包链接
它根本不是用来做本地开发链接的——composer global require 把包装进 ~/.composer/vendor/,只影响全局命令(比如 phpunit 或 larastan),对任何项目里的 require 都不生效。想让项目用上你本地改的 my-utils,这条路完全走不通。
真正起作用的是 repositories + type: "path"
这是 Composer 唯一原生支持的本地包共享机制,不需要镜像、不走网络、修改即生效。关键在两步:
- 被共享的包必须有合法的
composer.json,且name字段要符合vendor/name格式(如"name": "acme/utils") - 主项目中往
repositories数组里加一条:{"type": "path", "url": "../acme-utils"},路径是相对于当前项目根目录的相对路径 - 然后
composer require acme/utils:dev-main(分支名要带dev-前缀才能触发 path 模式)
安装后 vendor/acme/utils 是个符号链接,指向你本地的 ../acme-utils 目录。
path 模式下 require 的版本写法很关键
Composer 对 type: "path" 仓库的解析逻辑和普通镜像完全不同:它不查 packages.json,而是直接读目标目录下的 composer.json,并强制把分支名映射为 dev-xxx 版本号。
- 写
"acme/utils": "dev-main"→ 会链接main分支 - 写
"acme/utils": "dev-develop"→ 链接develop分支 - 写
"acme/utils": "1.0.x-dev"或"dev-master"→ 会失败,因为本地目录没对应分支 - 如果想锁定某次提交,得用
"acme/utils": "dev-main#abc123"
为什么不用 symlink 手动建链接
手动 ln -s 看似简单,但绕过了 Composer 的 autoload 注册、脚本钩子(如 post-autoload-dump)、依赖校验和 composer.lock 记录。一旦运行 composer update 或队友拉代码,链接就断了,lock 文件里也找不到来源依据。
而 type: "path" 是 Composer 官方机制,composer install 会把它当真实包处理:生成正确的 autoload 映射、记录在 lock 文件里、支持 --no-dev 过滤、甚至能配合 composer dump-autoload --classmap-authoritative。
唯一要注意的是:这个机制只适合开发环境。上线前必须把 repositories 里的 path 条目删掉,改用真实 Git 仓库或私有 Packagist,否则 CI 构建会因路径不存在直接失败。


















