--prefer-source仅在包声明source字段时生效,否则静默回退至dist;需检查composer.json的source配置、清除已存在包或lock文件,并配合--keep-vcs保留.git目录。

--prefer-source 不是万能开关,它只在包明确支持 source 安装时才生效;否则会被静默忽略,vendor 里依然没 .git 目录。
为什么加了 --prefer-source 还是没有 .git 目录?
最常见原因是目标包的 composer.json 没声明 source 字段——只写了 dist 地址,或者 "type": "package" 这类非 VCS 类型。Composer 遇到这种情况不会报错,而是自动 fallback 到 --prefer-dist 行为。
- 用
composer show vendor/package --all查看输出中是否有非空的source行(格式类似"source": { "type": "git", "url": "https://github.com/xxx/yyy.git", "reference": "abc123" }) - 进
vendor/vendor/package目录后执行ls -A | grep git,确认是否真没.git - 私有仓库若 HTTPS 克隆失败(如缺 token)、或 SSH key 未配置,也会 fallback 到 dist,日志里会写
Cloning failed, falling back to dist
如何只让某一个包走 source,其他保持 dist?
不能靠多次命令混用(比如先 require --prefer-source 再 require --prefer-dist),Composer 会以最后一次偏好为准。真正可靠的方式是改 composer.json 的 repositories 配置:
- 在
repositories里加一条vcs类型条目,url指向该包的 Git 地址(可以是 fork 后的地址) -
require中写对应包名和版本(如"monolog/monolog": "dev-main"),Composer 会自动选 source 方式安装 - 这样既不影响其他包,又绕过了原包是否声明
source的限制
示例片段:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/yourname/monolog"
}
],
"require": {
"monolog/monolog": "dev-main"
}
}
已安装的包怎么从 dist 切换到 source?
composer install --prefer-source 对已存在的包无效——Composer 默认跳过。必须显式触发重装:
- 删掉对应目录:
rm -rf vendor/monolog/monolog,再跑composer install --prefer-source - 或直接更新单个包:
composer update monolog/monolog --prefer-source - 如果
composer.lock里记录的是 dist 类型,且你想全量转 source,得先删composer.lock再重装(否则 lock 文件会锁死旧方式)
项目级启用 source 的安全写法
全局设 COMPOSER_PREFER_SOURCE=1 或 composer config --global prefer-source true 很危险,CI 和部署脚本可能误用。更稳妥的是在项目 composer.json 里用 preferred-install 精细控制:
- 全项目默认 source:
"preferred-install": { "*": "source" } - 仅对开发分支包启用:
"preferred-install": { "dev-*": "source", "*": "dist" } - 只针对特定包:
"preferred-install": { "monolog/monolog": "source", "*": "dist" }
注意:这种配置只影响新安装或 update,不会自动重拉已存在的 dist 包——仍需手动清理或指定 --prefer-source。
最容易被忽略的一点:即使成功拉下 .git,你改的代码也大概率会在下次 composer update 时被覆盖,因为 lock 文件锁的是 commit hash。临时调试可以,但长期 patch 必须配合 fork + 修改 repositories + 固定分支引用,否则改完就丢。


















