直接改 vendor 文件会丢失,因 composer 将其视为只读快照;必须用 --discard-changes 强制还原,或通过 cweagans/composer-patches 插件在 install 时自动打补丁。

直接改 vendor 里的文件会丢,不是 bug 是设计
Composer 把 vendor/ 当作只读快照,只要你编辑过任意一个文件(哪怕只是加了 var_dump),下次运行 composer install 或 composer update 就会中断,并报错:
The package vendor/package-name has modified files. Changes will be discarded. Use --discard-changes to overwrite.
这不是卡住,是 Composer 主动拒绝执行——它不区分你改的是核心逻辑还是 README,也不判断那几行有没有用。所谓“强制覆盖”,本质是丢弃+重装,不会保留你任何一行修改。
-
--discard-changes必须显式带上才生效,不写就停住不动 -
composer dump-autoload、composer clear-cache完全无效,它们不碰vendor文件内容 - 删整个
vendor/再重装比--discard-changes更慢,还会丢失 classmap 缓存等优化
cweagans/composer-patches 是目前最稳的补丁方案
Composer 本身没有 patch 命令,所有“打补丁”行为都依赖插件在 install 或 update 时调用系统 patch 命令完成。推荐用 cweagans/composer-patches(非 vaimo/composer-patches,前者更新更勤、文档更清晰):
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 安装:
composer require --dev cweagans/composer-patches:^1.7 - 安装后自动启用,无需额外配置 autoload
- 必须删掉
vendor/和composer.lock后再运行composer install,否则旧缓存包跳过补丁阶段 - 全局配置如
composer config --global store-auths false可能干扰插件读取本地composer.json,临时取消再试
extra.patches 配置必须写对位置和格式
补丁声明必须放在项目根目录的 composer.json 中的 extra.patches 字段下,不能塞进 repositories、scripts 或子包里:
- 键名必须是标准包名:
"monolog/monolog",不能写成"./vendor/monolog/monolog"或"monolog" - 值必须是对象,每个子键是描述(仅日志显示),值是补丁路径或 URL:
"Fix log truncation": "patches/monolog-truncate.patch" - 路径相对于
composer.json,所以patches/xxx.patch表示项目根目录下的patches/子目录 - 补丁文件必须是
git diff或diff -u格式,且路径前缀要匹配解压后的包结构,例如src/Handler/StreamHandler.php,不是vendor/monolog/monolog/src/Handler/StreamHandler.php - 补丁文件名别含空格或中文;推荐用短横线命名,如
laravel-session-race.patch
补丁生成时最容易错的三处细节
90% 的补丁失效,不是 diff 写错了,而是上下文路径和实际结构不匹配:
- 补丁里写的文件路径(
--- a/src/...php)必须和包解压后的目录结构一致,不能带vendor/xxx/前缀 - hunk offset(行号偏移)只要差 1 行,
patch命令就会失败并中止composer install,不会静默跳过 - 补丁生成时若用了
git diff,确保是在干净的包目录下操作;如果先改了vendor/再 diff,容易混入无关变更
真正麻烦的从来不是怎么让补丁跑通,而是改完之后没人知道那行 dump($x) 是谁加的、为什么加、会不会影响下次更新——这些细节,插件从不提醒你。










