Technical note

Git子模块常用操作

Git子模块本身的命令不多,真正容易漏掉的是主仓库只记录子模块的某个提交。子模块更新完成后,必须回到主仓库提交gitlink变化,否则其他人仍会取得旧版本。

参考

克隆包含子模块的项目

克隆时可以顺便初始化所有子模块:

git clone \
  --recurse-submodules \
  https://example.com/project.git

普通克隆完成后,也可以再初始化:

git submodule update --init --recursive

--recursive会继续处理子模块中的子模块。

添加子模块

添加时指定仓库地址、跟踪分支和本地目录:

git submodule add \
  -b main \
  https://example.com/common.git \
  app

git submodule status
git status
git commit -m '添加common子模块'

Git会新增.gitmodules,并在主仓库中记录子模块当前提交。主仓库记录的是一个确定的提交,不是子模块目录中的全部文件。

已有子模块可以修改跟踪分支:

git submodule set-branch --branch main app
git add .gitmodules
git commit -m '调整子模块跟踪分支'

这个分支配置只影响git submodule update --remote。普通的git submodule update仍以主仓库记录的提交为准。

更新子模块

拉取主仓库后,将子模块切换到主仓库记录的版本:

git pull
git submodule update --init --recursive

如果需要取得子模块远程分支上的最新提交:

git submodule update --remote app
git status
git add app
git commit -m '更新common子模块'

最后两步不能省。子模块更新后,主仓库中的gitlink也发生了变化,需要提交才能让其他人取得同一个版本。

直接进入子模块开发时也一样:

git -C app switch main
git -C app pull

git add app
git commit -m '更新common子模块'

修改仓库地址

子模块迁移到新地址后,需要同时更新.gitmodules和本地配置:

git submodule set-url \
  app \
  https://example.com/common.git

git submodule sync --recursive
git add .gitmodules
git commit -m '修改子模块地址'

停用和删除

只想清掉本地工作目录,不修改主仓库历史:

git submodule deinit app

以后可以重新初始化:

git submodule update --init app

从主仓库中删除子模块:

git rm app
git commit -m '删除common子模块'

不要直接删除子模块目录。git rm会同时处理主仓库中的gitlink和.gitmodules配置。