composer install/update 会丢弃本地修改是因为默认启用 discard-changes 行为,即删除已修改的 vendor 包并重装;可通过配置 "discard-changes": false 改为报错中止,强制人工决策。

composer install/update 时为什么会丢弃本地修改
因为 composer install 和 composer update 默认启用 discard-changes 行为:当某个包的 vendor 目录下有未提交的修改(比如你手动改过 vendor/foo/bar/src/Helper.php),Composer 会直接删掉整个包再重装,而不是报错或跳过——它假定你“不该动 vendor”。这看似安全,实则危险,尤其在调试、临时 patch 或 CI 中误操作后。
如何让 composer 拒绝覆盖已修改的包
核心是关闭自动丢弃,改用「报错中止」策略。Composer 不提供全局开关,但可通过以下方式生效:
- 在项目根目录
composer.json的"config"段里加:"config": { "discard-changes": false } - 或运行命令一次性设置:
composer config discard-changes false(写入composer.json) - 注意:该配置只对当前项目生效;全局配置(
composer config -g discard-changes false)不被支持,会忽略
discard-changes false 后的实际表现
不是“保留修改继续装”,而是“发现修改就停住并报错”。典型错误信息是:Changed files in vendor/package-name will be discarded. Use --force to overwrite. —— 这时你必须明确决定:要么删掉 vendor 手动改的文件,要么用 --force 强制覆盖,要么改用 patch 或 repositories 方式管理定制逻辑。
-
discard-changes: false对composer require和composer remove同样生效 - 如果某包被标记为
dev-main或使用path类型仓库,此配置不触发(Composer 认为这是你主动维护的) - CI 环境中建议始终开启,避免因缓存 vendor 导致“看似成功实则丢失补丁”
比 discard-changes 更靠谱的保护方式
靠 discard-changes: false 只是兜底报错,治标不治本。真正需要长期修改第三方代码时,应该绕过 vendor 直接干预:
- 用
composer config repositories.[name] type path指向本地 fork 目录,把修改放在自己仓库里 - 用
composer-patches插件管理补丁文件,配合extra.patches声明,可版本化、可复现 - 绝对不要在 CI 脚本里写
sed -i改 vendor 文件——下次install就失效,且无法审计
配置 discard-changes: false 是防止误操作的第一道锁,但它不会帮你保存修改,也不会告诉你哪行代码该进 Git —— 那得你自己划清边界。










