composer link 会被覆盖,因为它仅在 vendor/ 下创建软链接,不修改 composer.lock、不注册自动加载、不参与依赖解析;执行 composer update 会按 lock 文件重装 vendor/,导致软链接被删除并替换为正式包。

composer link 为什么会被覆盖
因为 composer link 只是给已安装包在 vendor/ 下建软链接,它不改 composer.lock,也不注册到 autoload,更不参与依赖解析。一旦执行 composer update(哪怕只更新其他包),Composer 会按 composer.lock 重装整个 vendor/,软链接自然被删掉、替换成从源下载的正式包。
-
composer link不是“永久注册”,只是临时开发捷径 - 它对
composer install完全无效——该命令只认lock文件,根本不看软链接 - 如果本地包用了
autoload.files或修改了命名空间,软链接后可能因自动加载路径错乱而报Class not found - CI/CD 流水线里执行
composer install,软链接必定消失,且不会报错,只会静默失效
想保留本地修改,别用 link,改用这三种方式
真正能抗住 composer install 的方案,必须把代码移出 vendor/,落到项目可控目录下:
- 用
autoload.files引入补丁文件:在composer.json中加"autoload": {"files": ["src/Patches/MonologHandler.php"]},然后在src/Patches/下写覆盖逻辑,composer dump-autoload即可生效 - 继承重写 + 容器替换:比如扩展
Monolog\Handler\StreamHandler,在自己的命名空间下重写write(),再通过框架容器(如 Laravel 的bind()或 ThinkPHP 的extend())替换原始服务 - fork 后用
repositories指向私有分支:在composer.json中配置"repositories": [{"type": "vcs", "url": "https://your-git-server/monolog/monolog"}],再 require"monolog/monolog": "dev-fix-log-context as 2.9.1",这样既可版本锁定,又可长期维护
已经 link 了,但 update 后丢了,怎么快速恢复
别重新 composer link,那只是治标。先确认当前 vendor/ 状态是否干净:
- 运行
composer show monolog/monolog,看输出的versions是不是你期望的本地分支(比如dev-main),如果不是,说明已被覆盖回稳定版 - 检查
vendor/monolog/monolog目录是否存在,以及是否是真实目录(不是软链接)——如果是目录,说明link已失效 - 若只是想临时调试,立刻进本地包目录,执行
composer link;但必须同步做两件事:git add -f composer.lock(忽略 .gitignore)、composer dump-autoload,否则 autoload 仍不认 - 若要长期保留,必须放弃
link,改用上面三种落地方式之一,否则每次install都得手动补一次
锁版本和软链接不是一回事,别混着用
很多人以为 "monolog/monolog": "2.9.1" + composer link 就能“既锁定又可调”,其实冲突:前者要求装 2.9.1,后者指向本地未打 tag 的 dev 分支,Composer 在 update 时会直接报 Root composer.json requires monolog/monolog 2.9.1, found monolog/monolog[dev-main] but it does not match the constraint.
- 要锁定,就别用
link;要用link,就别在composer.json里写死三位版本号 - 真需要“锁定 + 可调”,唯一可靠路径是 fork +
as别名:比如"monolog/monolog": "dev-your-fix as 2.9.1",这样 Composer 认为它满足约束,又能用你的代码 -
composer.lock里记录的是实际安装的 commit hash 或 dist sha256,不是软链接路径——所以它永远不知道你 link 过什么
最常被忽略的一点:软链接本身不解决 autoload 注册问题。即使 vendor/ 下是链接,如果本地包没声明正确的 autoload(psr-4 / classmap),composer dump-autoload 也不会把它扫进去。动手前先跑一遍 composer dump-autoload -o 并验证类能否 new 出来。











