如何拉取所有 Git 子模块的最新代码
git submodule update --remote --recursive 拉取所有子模块跟踪分支的最新提交;拉完父仓库要提交更新后的子模块引用。附初始化、嵌套、回退的完整命令。
一句话回答:git submodule update --remote --recursive——--remote 让子模块拉取其跟踪分支的最新提交(而不是父仓库记录的固定提交),--recursive 连带嵌套子模块。拉完逐层审查并提交已核对的子模块引用,别人才能同步到同样版本。
标准流程
# 首次克隆含子模块的仓库
git clone --recursive 仓库URL
# 或克隆后补初始化
git submodule update --init --recursive
# 更新前检查父仓库和嵌套子模块,先保存各自的未提交工作
# 子模块有独立工作区,父仓库 stash 不会自动保全其中改动
git status --short
git submodule foreach --recursive 'git status --short'
# 拉取所有子模块的最新代码
git submodule update --remote --recursive
# 父仓库提交引用更新
git diff --submodule=log
# 将下面路径替换为本次实际更新的子模块路径
git add -- path/to/submodule
git diff --cached --submodule=log
git commit -m "chore: 更新子模块到最新"
两种更新模式的区别
| 命令 | 行为 |
|---|---|
git submodule update |
检出到父仓库记录的提交(同步模式,默认) |
git submodule update --remote |
拉取子模块远程跟踪分支的最新提交(追新模式) |
日常同步别人更新用前者;主动追上游最新用后者。子模块跟踪哪个分支可在 .gitmodules 里配 branch = main。
嵌套子模块追到新版本后,还必须在它的直接父子模块内逐层提交 gitlink,再提交最外层引用;只提交顶层并不能保存所有嵌套引用变化。
嵌套与批量细节
git submodule update --init --recursive # 初始化+检出(含嵌套),克隆后一把齐
git submodule foreach --recursive 'git status --short' # 不盲目 pull 固定分支
git submodule status # 看各子模块当前提交
注意事项
- 子模块有未提交改动时更新可能失败或携带这些改动:先
git submodule foreach 'git status'检查,提交或 stash 后再更新 - 默认 checkout 更新策略通常产生 detached HEAD:正常,子模块本来按提交钉住;要基于它开发就进去建分支
- 父仓库不提交引用更新 = 白拉:别人 clone 时按你仓库里记录的提交检出,看不到你拉的新版本
常见问题(FAQ)
Q:git pull 会自动更新子模块吗?
A:不会自动检出。配 git config submodule.recurse true 后 pull 会连带更新子模块到记录的提交;按仓库需求启用,不建议未经评估修改全局行为。
Q:拉错了版本想回退?
A:先备份父仓库及各子模块的未提交改动。若引用尚未暂存,确认 HEAD 中的 gitlink 正是要恢复的版本后,在仓库根目录执行 git submodule update --init --recursive -- path/to/submodule。若已暂存或提交,先明确目标引用并审查差异;已共享更新优先用新提交回退,不盲用 HEAD~1、--force 或 reset --hard。
Q:CI 里怎么正确处理子模块?
A:clone 步骤加 --recursive,或 CI 步骤里 git submodule update --init --recursive;私有子模块还要给 CI 配好对应凭据(Deploy Key/Token)。
参考资料
本文依据官方资料核对,未进行现场运行测试;代码与配置示例需结合实际版本、权限和环境验证。