Composer 会中止 install 因 vendor 存未提交修改,这是保护机制;需 --discard-changes 强制重置,或用 fork、补丁、PSR-4 覆盖等持久方案。

Composer 会直接拒绝执行 composer install,只要它检测到 vendor/ 下任何包存在未提交的修改——这不是卡住,是明确中止,必须人工干预。
为什么 composer install 一碰就停?
Composer 把 vendor/ 当作只读快照,不是工作区。只要你改过哪怕一个 .md 或 .php 文件(比如调试时加了 dump()),它就会报错中断,典型提示包括:
Package vendor/package is not up to date. Changes will be discarded.There are uncommitted changes in vendor/package
这不是 bug,是保护机制:防止你忘了自己改过什么,结果被覆盖后出问题却找不到原因。
它不会自动跳过,也不会只覆盖“没改过的包”——只要有一个包脏了,整个命令就 halt。
强制还原的唯一安全方式:加 --discard-changes
这个参数不是开关,而是明确指令:丢弃所有本地修改,按 composer.lock 完整恢复。
-
composer install --discard-changes:最常用,不改 lock,只重置 vendor 文件 -
composer update --discard-changes:先更新依赖再丢弃修改——会改composer.lock,慎用
注意:--discard-changes 不等于 rm -rf vendor && composer install。它内部做的是 per-package diff + reset,更快、更精准,且保留 autoload 缓存结构。
别指望 composer dump-autoload 或 composer clear-cache 能绕过这个检查——它们根本不碰 vendor 文件内容本身。
想保留修改?别手动改 vendor
手动改 vendor/ 是临时行为,无法持久,也难协作。长期方案只有三个:
-
Fork + VCS 仓库:把包 fork 到自己账号,提交修改,然后在
composer.json的repositories里加{"type": "vcs", "url": "https://github.com/yourname/package"},再require对应分支(如"dev-main") -
补丁(patch):用
cweagans/composer-patches插件,把修改保存为.patch文件,声明在extra.patches里,每次install自动打上 -
PSR-4 覆盖 +
exclude-from-classmap:在composer.json中排除原文件路径,再用自定义命名空间映射到项目内(如"Tymon\": "app/Overrides/"),最后跑composer dump-autoload
这三者都要求你改完 composer.json 后必须执行 composer dump-autoload,否则新路径不会生效。
vendor/bin 删除失败?大概率是进程占着文件
Windows 下常见现象:composer install 卡在 “Could not delete vendor/bin” —— 这不是权限问题,是句柄被锁。
- PHPStorm、VS Code、甚至杀毒软件(如 Kaspersky 的
avp.exe)可能长期持有vendor/bin下脚本的文件句柄 - 先关掉所有 IDE,再用
resmon(资源监视器)搜索vendorin,找到对应进程并结束 - 或者临时用管理员权限运行命令行,再执行
composer install --no-scripts --no-plugins跳过触发占用的阶段
Linux/macOS 用户遇到类似问题,可试 lsof +D vendor/bin 查进程,再 kill 掉。
真正麻烦的从来不是怎么删掉或覆盖,而是谁在什么时候改了哪一行、为什么改、会不会影响下次更新——这些上下文,--discard-changes 从不提醒你。











