导语:git submodule 命令适用于有子模块的项目,本文对常用的命令进行罗列并介绍用法。
假如当前存在两个项目:git-main-project(主项目)、git-submodule-project(子模块)。
添加子模块
在主项目的根目录执行:
git submodule add {http/ssh}
之后会在主项目的根目录生成 .gitmodules 文件,用于记录子模块在信息和子模块同名的文件夹,用于存放子模块。例如,在 git-main-project 根目录下执行:
git submodule add git@github.com:ZhangDaZongWei/git-submodule-project.git
则会生成 .gitmodules 文件和 git-submodule-project 文件夹。
clone 含有子模块的项目
# 克隆主项目
git clone {http/ssh}
# 初始化本地配置文件,即对子模块路径进行注册
git submodule init
# 拉取所有的数据和 checkout 合适的子模块commit
git submodule update
# git submodule init 和 git submodule update 的组合,且会拉取嵌套的子模块
git submodule update --init --recursive
可以将上述多条命令替换成一条命令:
# clone 时一同初始化并checkout子模块commit,且会拉取嵌套的子模块(即子模块又包含它引用的子模块)
git clone --recurse-submodules {https/ssh}
更新子模块
更新子模块和更新主项目命令一样:
# 进入子模块
# 切换到相应的分支
git checkout {branchName}
git fetch
git merge {origin/branchName}
也可以不进入子模块,直接在主项目中更新:
# 在主模块,但是这样默认是子模块的 master 分支
# 若不指定 submoduleName 则会更新所有的子模块
git submodule update --remote {submoduleName}
# 可以通过以下命令设置特定的分支
git config -f .gitmodules submodule.{submoduleName}.branch {branchName}
无论哪种方式更新,都会在主项目生成子模块更新的 commit 信息,可见主项目只需要记录子模块的 commit 信息即可。当主项目 push
后,其远程仓库里的子模块也锁定为最新的。
更新主项目
当更新主项目时,也要兼顾到子模块的更新:
# 更新主项目,例如
git pull
但是这样只会拉取到子模块 commit 变更记录,并不会主动更新子模块,还需要执行:
# 参数 --init 和 --recursive 以防止主项目又新添加了子模块,或者子模块中新增嵌套的子模块
git submodule update --init --recursive
可以替换成一条命令:
git pull --recurse-submodules
更改子模块时,需要注意的是一定要 checkout
到某一个具体分支,因为当在主项目中使用 git submodule update
命令更新子模块时,会子模块处于 detached HEAD 的状态,即没有本地分支跟踪变更,会导致在此状态下子模块的 commit,在下一次 update 时丢失。即如果不 checkout
具体的分支,会覆盖掉已更新的内容。
# 进入子模块
cd git-submodule-project
# checkout 分支
git checkout {branch}
# 做一些更改后
git add .
git commit -m "xxx"
git push
同样地,主项目中也会生成一个子模块更新的 commit 记录。
有时当更改完子模块后,忘记了 push
,但是在主项目更改后却 push
了,所以远程仓库的子模块未更新,导致其他人不会获取子模块的更新,可以使用以下命令防止这种情况:
# 在主模块 push 之前,检查子模块是否 push,包括嵌套子模块
git push --recurse-submodules=check
# 在主模块 push 之前,自动 push 子模块,包括嵌套子模块
git push --recurse-submodules=on-demand
最后
更详细的信息请查看:
git submodule 文档 https://git-scm.com/book/en/v2/Git-Tools-Submodules
上述文章表述或者在实践中有任何问题,欢迎联系我。
注意:本文章只是 git 系列 的其中一篇,这个系列致力于罗列不常用或者使用起来有一定难度的 git命令及其用法。