前言

项目中经常包含别人维护的模块,在 git 中以子模块的形式引用提交,一些命令总是记不住,往往都是现用现查,干脆整理记录子模块相关的基础命令,懒得反复到处找。

添加submodule

命令:

1
git submodule add <repo_url> <local_path>

一个实例:

1
2
3
4
5
6
7
8
9
10
$ git submodule add -b master --depth=1 https://github.com/fluid-dev/hexo-theme-fluid.git themes/fluid
Cloning into 'C:/Users/Administrator/Documents/Git/hexoBlog/themes/fluid'...
remote: Enumerating objects: 214, done.
remote: Counting objects: 100% (214/214), done.
remote: Compressing objects: 100% (202/202), done.
Receiving objects: 100% (214/214), 536.96 KiB | 148.00 KiB/s, done.
Resolving deltas: 100% (5/5), done.
remote: Total 214 (delta 5), reused 88 (delta 2), pack-reused 0
warning: LF will be replaced by CRLF in .gitmodules.
The file will have its original line endings in your working directory

添加完成后,可以查看本地子模块状态:

1
2
$ git submodule status
15310a9d87a2300f9292dd66b2c243775d46f9c6 themes/fluid (v1.9.5-4-g15310a9)

添加 submodule 后,会产生以下变化:

  1. 在仓库根目录下生成一个 .gitmodules,文件,内容:
1
2
3
[submodule "themes/fluid"]
path = themes/fluid
url = https://github.com/fluid-dev/hexo-theme-fluid.git
  1. 仓库配置 .git/config 中也会相应添加:
1
2
[submodule "themes/fluid"]
url = https://github.com/fluid-dev/hexo-theme-fluid.git
  1. 生成 .git\modules\themes\fluid 文件夹,存储的是自模块 git 版本管理信息

最后,将本地变更提交同步到线上仓库就完成了。

更新submodule

引自网络的图片示例

当上游仓库有新版本时,我们可以在集成Git操作界面上拉取更新,也可以使用以下命令完成:

1
2
3
# 默认只会克隆子模块目录,需要在项目根目录执行 init 命令完成子模块内容的同步
git submodule init
git submodule update

也可以用以下组合命令一次完成子模块更新:

1
git submodule update --init --recursive

当然,我们在克隆主项目时可以同时将子模块一并拉取:

1
git clone --recurse-submodules <repo_url> 

当我们决定以 submodule 方式管理某个仓库时,建议相应 submodule 所有的增删改都单向操作,即:

  • 在主项目中,只单向从 submodule 上游拉取更新,其他所有的变更都该让 submodule 上游去完成

修改submodule

有时候想变更 submodule 信息,我们可以删除后重新添加,也可以直接修改。

同样用上面的实例,找到前文添加子模块时所述的变更 .gitmodules,修改仓库 URL:

1
2
3
[submodule "themes/fluid"]
path = themes/fluid
url = git@github.com:fluid-dev/hexo-theme-fluid.git #新的 URL

然后运行子模块同步命令:

1
2
$ git submodule sync
Synchronizing submodule url for 'themes/fluid'

接下来将变更按 git 规范提交即可。当然,也可以用 git submodule set-url 命令来完成,有兴趣的自行摸索。

删除submodule

删除子模块稍微复杂一点:

1
2
3
4
# 逆初始化模块,其中{MOD_NAME}为模块目录,执行后可发现模块目录被清空
git submodule deinit {MOD_NAME}
# 删除.gitmodules中记录的模块信息(--cached选项清除.git/modules中的缓存)
git rm --cached {MOD_NAME}

实例:

1
2
3
4
Administrator@10_0_12_17 MINGW64 ~/Documents/Git/hexoBlog (main)
$ git submodule deinit themes/fluid
$ git rm --cached themes/fluid
rm 'themes/fluid

命令执行完将 themes/fluid.git/modules/themes/fluid 目录删除,最后提交变更。

git submodule 命令总览

1
2
3
4
5
6
7
8
9
10
11
12
git submodule [--quiet] [--cached]
git submodule [--quiet] add [<options>] [--] <repository> [<path>]
git submodule [--quiet] status [--cached] [--recursive] [--] [<path>…​]
git submodule [--quiet] init [--] [<path>…​]
git submodule [--quiet] deinit [-f|--force] (--all|[--] <path>…​)
git submodule [--quiet] update [<options>] [--] [<path>…​]
git submodule [--quiet] set-branch [<options>] [--] <path>
git submodule [--quiet] set-url [--] <path> <newurl>
git submodule [--quiet] summary [<options>] [--] [<path>…​]
git submodule [--quiet] foreach [--recursive] <command>
git submodule [--quiet] sync [--recursive] [--] [<path>…​]
git submodule [--quiet] absorbgitdirs [--] [<path>…​]