composer install 不会更新包,它仅按 composer.lock 还原依赖;真正触发更新的是 composer update 或无 lock 时的首次 install。

composer install 本来就不会更新包,别被名字骗了
很多人看到 composer install 就以为它会“安装新东西”或“升级旧东西”,其实不是。composer install 的唯一职责是**严格按 composer.lock 文件还原依赖状态**:已装的版本不变,没装的按 lock 装,多出来的删掉(除非加 --no-scripts 等参数干扰)。它根本不读 composer.json 里的版本约束,也不做任何解析或升级决策。
所以,“阻止 composer install 更新某个包”这个需求本身是伪命题——它压根不会主动更新任何包。真正会触发更新的是 composer update 或没 lock 文件时的首次 install(此时退化为 update 行为)。
真正要防的是 composer update 拉高版本
如果你发现 composer install “变了包”,大概率是因为:lock 文件被改过,或者根本不存在。这时候 Composer 会 fallback 到解析 composer.json 并求解最新兼容版本——这本质是 update 行为。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 检查
composer.lock是否提交到 Git:没提交 = 每次 install 都可能变 - 确认 CI/CD 构建前是否执行了
composer update:一旦执行,lock 就被重写 - 警惕
composer install --no-dev在无 lock 下的副作用:它仍会全量解析 require,只是跳过 require-dev
可靠冻结包版本的三种实操方式
想让某个包(比如 monolog/monolog)在后续所有 composer update 中纹丝不动,必须干预依赖解析阶段。以下方法按推荐度排序:
-
写死精确版本号:把
"monolog/monolog": "^2.9"改成"monolog/monolog": "2.9.1"(去掉^或~),然后运行composer update monolog/monolog并立刻提交新的composer.lock。这是生产环境唯一可审计、可复现的方式 -
用
conflict拦截冲突版本:在composer.json根级加"conflict": {"monolog/monolog": ">=3.0.0"}。依赖解析时一旦发现匹配版本,直接报错退出,强制你人工介入 -
用
replace声明已提供:加"replace": {"monolog/monolog": "*"}。Composer 会认为该包“已存在”,不再安装或升级——但风险极高:若其他包 require 它而你本地没实现,运行时必崩
别碰手动改 lock 或 --without 这类高危操作
直接编辑 composer.lock 把某个包的 version 改小,或用 composer update --without=monolog/monolog,看似能跳过,实际埋雷:
- 改 lock 文件会导致下次
composer install因哈希校验失败中止:“The lock file is not up to date” -
--without不是“跳过更新”,而是“剔除整个子树”,如果被剔除的包是其他依赖的硬依赖(如symfony/console → symfony/polyfill-php81),命令直接报错退出 - 镜像源(阿里云/腾讯云)不支持 exclude 过滤,所有 URL 参数或配置项修改都无效——排除逻辑只能落在本地
composer.json和依赖解析阶段
冻结一个包,本质是控制它的版本约束如何被解析;而解析只发生在 update 或无 lock 的 install 里。搞清这点,就不会在错误的地方使劲了。

















