子模块
有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 这个项目一般是公共库,而公共代码库的版本管理是个麻烦的事情 这时候我们可以使用 Git submodule 来管理
添加
首先将一个已存在的 Git 仓库添加为的子模块。 你可以通过在
git submodule add 仓库地址 路径
- 仓库地址是指子模块仓库地址
- 路径指将子模块放置在当前工程下的路径,默认子模块放在和主项目同层级下,如果要设置其他位置,需要指定路径
注意:路径不能以 / 结尾(会造成修改不生效)、不能是现有工程已有的目录(不能順利 Clone)
命令后面加上想要跟踪的项目的相对或绝对 URL 来添加新的子模块。 在本例中,我们将会添加一个名为 “DbConnector”的库。
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
命令执行完成,会在当前工程根路径下生成一个名为“.gitmodules”的文件,其中记录了子模块的信息
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
子模块的修改,需要去子module的Git 仓库中提交,并回到主项目更新module
删除
submodule的删除稍微麻烦点:首先,要在“.gitmodules”文件中删除相应配置信息。然后,执行“git rm –cached ”命令将子模块所在的文件从git中删除。
克隆含有子模块的项目
-
克隆一个含有子模块的项目。 当你在克隆这样的项目时,默认会包含该子模块目录,但子模块没有任何文件
必须运行两个命令:
git submodule init用来初始化本地配置文件,git submodule update则从该项目中抓取所有数据并检出父项目中列出的合适的提交。这时候子模块就被完整的clone下来了
-
还有更简单一点的方式。 如果给 git clone 命令传递
--recurse-submodules选项,它就会自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。例如:
git clone --recurse-submodules https://github.com/chaconinc/MainProject -
如果你已经克隆了项目但忘记了
--recurse-submodules可以运行
git submodule update --init将git submodule init和git submodule update合并成一步。如果还要初始化、抓取并检出任何嵌套的子模块, 请使用简明的git submodule update --init --recursive -
本地子项目修改后,如果未push, 然后主项目直接推送到远端仓库,会导致其他人pull代码无法运行,因为无法得到子项目的改动,针对这种情况,主项目push前,要检查所有子项目的修改都push成功
git push命令接受可以设置为 “check” 或 “on-demand” 的--recurse-submodules参数。 如果任何提交的子模块改动没有推送那么 “check” 选项会直接使push操作失败。git push --recurse-submodules=check如果你想要对所有推送都执行检查,那么可以通过设置让它成为默认行为
git config push.recurseSubmodules check这样如果如果子项目推送失败,主项目也会失败,如果不想检查,可以使用
on-demand恢复默认状态git config push.recurseSubmodules on-demand
子模块技巧
子模块遍历
有一个 foreach 子模块命令,它能在每一个子模块中运行任意命令。 如果项目中包含了大量子模块,这会非常有用。
例如保存当前所有子模块的进度
git submodule foreach 'git stash'
别名
你可能想为其中一些命令设置别名,因为它们可能会非常长而你又不能设置选项作为它们的默认选项。 我们在 Git 别名 介绍了设置 Git 别名, 但是如果你计划在 Git 中大量使用子模块的话,这里有一些例子
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
\