在 Git 项目中,需要包含别的 Git 项目,我们希望能够独立的使用这两个项目。比如我们的博客是一个 Git 项目,而我们需要在博客中包含别人的项目作为博客主题,我们希望能够在自己写博文后 push 不影响博客主题仓库,同时希望能够独立使用主题仓库,这样我们就可以获取最新的主题。

这个时候需要用到 git submodule。在使用 submodule 之后,两个项目便相对独立(或者多个 submodule,那么就是多个项目相对独立)。下面介绍子模块常用的用法:

使用子模块

添加子模块

在 Git 项目中包含别的 Git 项目,不能够直接到相应文件夹 clone,而需要使用 git add submodule 命令,可以将这个命令视为子模块版本的 git clone

git add submodule git@github.com/example/example.git submodule

上面的命令将项目克隆到 submodule 目录。会发现根目录生成了一个 .gitmodule 文件,这个文件用于保存子模块信息。

查看子模块

使用 git submodule 命令查看当前项目的子模块。

更新子模块

在项目中使用 git update 父模块并不会更新子模块。(别的操作同理,我们在项目中使用的各种以前使用的 git 操作都只会对父模块产生作用)

使用 git submodule add 添加子项目。

操作子模块

在子模块的文件夹内部,我们的各种操作都是对子模块的项目产生作用,比如 push 就是将子模块 push 到子模块的 remote repository。

所以需要单独修改子模块,只需要 cd 到子模块内,把子模块当成一个普通的 git 项目即可。

克隆含有子模块的项目

克隆包含子模块的项目有两种方法:

  1. 先克隆父项目,再更新子模块
  2. 递归克隆整个项目。

先克隆父项目,再更新子模块

这种方法有以下步骤:

  1. 克隆父项目:git clone xxx。注意这种情况下,像之前说的,在父项目中的操作,只对父项目产生作用,所以子项目不会被 clone。
  2. 查看子模块:git submodule。会发现子模块前面有一个 -,说明子模块文件还未被 clone(为空文件夹)。
    $ git submodule
    -e33f854d3f51f5ebd771a68da05ad0371a3c0570 xxx
    
  3. 初始化子模块:git submodule init。在父模块 clone 之后运行一次,就行了。
  4. 更新子模块:git submodule update。运行后子模块被 clone,整个项目就 ready 了。

递归克隆整个项目

clone 的时候,添加 --recursive 指令,递归克隆子模块,一步到位。

git clone xxxx --recursive

删除子模块

删除子模块比较麻烦,需要手动删除相关的文件,否则在添加子模块时有可能出现错误

以删除 assets 文件夹为例

  1. 删除子模块文件夹

    $ git rm --cached assets
    $ rm -rf assets
    
  2. 删除 .gitmodules 文件中相关子模块信息

    [submodule "assets"]
        path = assets
        url = https://github.com/maonx/vimwiki-assets.git
    
  3. 删除 .git/config 中的相关子模块信息

    [submodule "assets"]
        url = https://github.com/maonx/vimwiki-assets.git
    
  4. 删除 .git 文件夹中的相关子模块文件

    $ rm -rf .git/modules/assets