暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Git submodule 原理解析

生有可恋 2022-02-11
3887

当 git 代码库中使用了子模块(submodule)时,情况变得复杂,此时我们需要了解在 git 库中都发生了什么,如何查看 submodule 状态。


首先我们拉取一个含子模块的仓库,查看其中的文件结构

git clone git://github.com/hyang0/vimhome.git ~/.vim


目录中有一个 .gitmodules 的文件,里面包含了所引用的子模块

$ cat .gitmodules
[submodule "bundle/vim-powerline"]
path = bundle/vim-powerline
url = git://github.com/Lokaltog/vim-powerline.git
[submodule "bundle/nerdtree"]
path = bundle/nerdtree
url = git://github.com/scrooloose/nerdtree.git
[submodule "bundle/tagbar"]
path = bundle/tagbar
url = 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/nerdtree
bundle/tagbar
bundle/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 提交中


参考:

  1.  https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97

  2. https://stackoverflow.com/questions/42417294/why-does-git-fail-to-fetch-specific-valid-submodule-for-a-given-commit-and-how-t



文章转载自生有可恋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论