当 git 代码库中使用了子模块(submodule)时,情况变得复杂,此时我们需要了解在 git 库中都发生了什么,如何查看 submodule 状态。
首先我们拉取一个含子模块的仓库,查看其中的文件结构
git clone git://github.com/hyang0/vimhome.git ~/.vim

目录中有一个 .gitmodules 的文件,里面包含了所引用的子模块
$ cat .gitmodules[submodule "bundle/vim-powerline"]path = bundle/vim-powerlineurl = git://github.com/Lokaltog/vim-powerline.git[submodule "bundle/nerdtree"]path = bundle/nerdtreeurl = git://github.com/scrooloose/nerdtree.git[submodule "bundle/tagbar"]path = bundle/tagbarurl = git://github.com/majutsushi/tagbar.git
在仓库刚 clone 下来时,子模块的目录是空的
Administrator@MS-OIPXDHWZIYJO MINGW64 ~/.vim (master)$ ls bundle/nerdtree/ tagbar/ vim-powerline/Administrator@MS-OIPXDHWZIYJO MINGW64 ~/.vim (master)$ find bundle/bundle/bundle/nerdtreebundle/tagbarbundle/vim-powerline
此时查看子模块状态,可以看到每一行前有一个减号,代表子模块还没有初始化,还是个空目录
$ git submodule

如果想clone仓库时顺便把子模块一起clone下来,在使用 git clone 时加上 --recurse-submodules 参数即可。
$ git clone --recurse-submodules git://github.com/hyang0/vimhome.git ~/.vim

当获取到子模块后代码后,子模块的空目录被初始化为git仓库,此时再次执行 submodule 命令,仓库前的减号去掉了,代表子模块已初始化

初始化后的子模块是个完整的git库,含.git目录

这个过程可以分步执行
$ git submodule init$ git submodule update

当执行 git clone --recurse-submodules 时,相当于执行了
git submodule init && git submodule update
git子模块实际上只保存了两部分信息
在 .gitmodules 中保存子仓库的远程URL
在 commit 中保存引用的子模块的 commit-id
可以在 git log 中查看已提交的子模块的 commit-id
$ git log -p| grep -B 4 +Subproject

git submodule 并不会取每个子模块的最新代码,而只会取所引用的对应的commit-id 的代码。
当执行 git submodule init 时,git 会在 .git/config 文件中将 .gitmodules 的模块内容写到 .git/config 中。

如果此时将 .git/config 中的 submodule 内容删掉,再查看子模块信息,会发现每个 commit-id 前又多了个减号。

git submodule init 的作用就是将子模块的信息写到 .git/config中
git submodule update 的作用是将子模块的空目录 clone 成对应版本的 git 仓库。当目录为空时,git submodule 显示的子模块不带版本信息。

如果将 git submodule init 的动作分解手动执行,可以分解成如下两步:
git clone <子模块的-git-url> <本地目录>
cd <子模块目录> ; git checkout <commit-id>

理解了 git submodule 实际上就是 URL 加 commit-id ,就好办了。git 子模块的信息存储在如下位置
.gitmodules # 本地目录与远程 git-url 之间的关系
.git/config # 当执行 git submodule init 时添加
所引用的子模块的版本 # 存储在 commit 提交中
参考:
https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97
https://stackoverflow.com/questions/42417294/why-does-git-fail-to-fetch-specific-valid-submodule-for-a-given-commit-and-how-t




