composer 不拉 git 子模块,因其仅下载包(git clone 或 zip),不处理子模块逻辑;需通过 composer.json 中配置 post-install-cmd 和 post-update-cmd 执行 git submodule update --init --recursive 自动初始化,或改用 --prefer-dist 跳过 git 操作。

为什么 composer update 不拉 Git 子模块?
因为 Composer 从不处理 Git 的任何子模块逻辑——它只管下载包(git clone 或 .zip),clone 完就结束。子模块目录会被 Git 当作“未跟踪的空目录”留在那里,git status 显示灰色文件夹,git submodule status 直接报错或无输出,这就是典型症状。
怎么让 composer update 后自动初始化子模块?
在项目根目录 composer.json 的 "scripts" 段里加两条命令:
"post-install-cmd": [ "git submodule update --init --recursive" ], "post-update-cmd": [ "git submodule update --init --recursive" ]
注意这几点:
- 确保开发机已安装 Git 且在
$PATH中,否则脚本静默失败 - 如果子模块路径含空格或特殊字符,用
cd vendor/xxx/package && git submodule...替代全局命令更稳妥 - 多个包各自带子模块?不要堆在一条命令里,拆成独立脚本行,避免一个失败阻塞全部
- CI 环境若禁用 Git(如某些 Docker 镜像),该脚本会直接退出非零码,需提前检查
is_dir('.git')或跳过
--prefer-dist 能绕过子模块问题吗?
能,但有前提:
- 目标包必须在 Packagist 上发布过
.zip归档(绝大多数开源包都满足) - 执行
composer install --prefer-dist或在composer.json里设"preferred-install": {"*": "dist"} - 它完全跳过
git clone,自然没子模块什么事——但你也拿不到.git目录,无法做本地 patch 或调试源码 - 私有包若只支持
vcs类型,--prefer-dist会退化为 clone,子模块问题照旧
开发自己写的 Composer 包时,子模块怎么不坑队友?
如果你是包作者,别在 main 分支直接 push 未初始化的 submodule 提交。正确做法:
- 每次打 tag 前,先运行
git submodule update --remote --recursive同步子模块到最新兼容提交 - 再
git add .gitmodules vendor/submodule-path提交变更 - 确认 CI 流程中包含
git submodule sync && git submodule update --init --recursive步骤 - 在 README 里写明:“本包含子模块,建议用
composer install --no-scripts后手动进vendor/your/package执行git submodule update --init”——给无法自动化的环境留退路
最易被忽略的一点:子模块 URL 是相对路径还是绝对 SSH 地址?私有仓库用 git@ 地址时,所有协作者机器都得配好对应 SSH key,否则 submodule update 卡在权限拒绝,连错误提示都可能被 Composer 脚本吞掉。











