composer.lock 是项目依赖的精确版本快照,记录所有包的完整版本、下载地址、校验和及依赖树结构,必须提交至 Git 以保障构建可重现;应用项目须提交,库项目则不应提交。
它不是临时生成、可随意删掉的中间产物,而是项目当前所有依赖(包括子依赖)的精确版本快照。只要存在 composer.lock,composer install 就会严格按它安装——不联网解析、不重新选版本、不考虑 composer.json 里的 ^2.0 或 ~1.5 这类范围约束。
"monolog/monolog": "2.9.1",不是 "^2.0"
dist 下载地址和 SHA-256 校验和,
确保下载内容未被篡改psr/log 被哪个包间接引入、用了哪个版本,都写得清清楚楚不提交 composer.lock,就等于把“线上跑的代码到底依赖什么版本”这个问题交给运气。本地能跑,CI 报错,生产崩了查不出原因——90% 都是这个文件没进仓库导致的。
composer install 时,靠的就是 lock 文件跳过解析;没它,每次构建都可能拉到不同小版本composer install 能立刻还原当时那套依赖;没 lock 文件,你根本不知道那个 commit 对应哪套依赖composer audit)依赖 lock 文件里的完整依赖图谱,没它就扫不出深层漏洞注意:只有应用项目(application)才必须提交;如果你在写一个会被别人 require 的开源库(library),则不应提交自己的 composer.lock。
composer.lock 是自动生成的 JSON,结构复杂、字段多、嵌套深,手动改极易出错。一旦冲突,标准解法只有一个:
composer.json 的冲突(比如两人同时加了新包,或改了同一包的版本)composer.json
composer update(或更精准地用 composer update vendor/package)composer.lock
这样生成的 lock 文件才是逻辑一致、可验证的。强行保留某一方的 lock + 手动 patch,轻则 autoload 失败,重则运行时抛出 Class not found 或方法签名不匹配。
一句话区分:install 是还原,update 是变更。绝大多数时候,你只需要 composer install。
composer install(含 --no-dev)composer require monolog/monolog 后自动更新 lock,再提交composer update monolog/monolog,验证通过后再提交 lockcomposer update --with-dependencies 或 composer audit --fix
最常踩的坑是:以为 composer install 会“自动更新”——它不会。它只认 lock 文件;没有 lock,才退化成解析行为,而这恰恰是你要避免的不可控状态。
真正关键的不是记住命令,而是理解「lock 文件 = 可重现性的唯一事实来源」。哪怕你用 Docker、用 Nix、用全栈隔离环境,只要构建阶段调了 composer install,它就绕不开这个文件。忽略它,就等于放弃对依赖的控制权。