Git submodule 简明使用指南

有时候,一个项目需要使用另一个 Git 仓库,也许是第三方库,或者独立的项目,那如何让所有的 Git 仓库在这一项目目录里共存呢? Git submodule 便派上了用场。

什么是 Git submodule

Git submodule 即 Git 子模块,子模块允许将一个 Git 仓库作为另一个 Git 仓库的子目录。同一个项目目录,但是独立的 git 记录和提交。

如何新建 Git submodule

git submodule add <子模块git地址> <存放的文件路径以及文件名>

如果需要指定子模块某分支的话(需要 Git 1.8.2+)

git submodule add -b <子模块分支> <子模块git地址> <存放的文件路径以及文件名>

然后git add . && git commit 保存记录。

image.png
image.png

执行 tree -a 可以查看当前 repoA 目录结构变化如下

.
├── .git 
│   ├── HEAD
│   ├── branches
│   ├── config
│   ├── ...
│   ├── modules # git记录新增modules
│   │   └── plugins
│   │       └── repoB
│   │           ├── HEAD
│   │           ├── branches
│   │           ├── config
│   │           ├── ...
│   │           └── refs
│   └── refs
├── .gitmodules #新增
├── README.md
└── plugins # 新增子模块目录
    └── repoB
        ├── .git # 子模块git记录
        └── README.md
image.png
image.png

如何克隆含有子模块的项目

如果第一次克隆,使用--recurse-submodules参数

git clone --recurse-submodules <git仓库地址>

image.png

在已克隆的项目里克隆子模块

  1. 正常克隆仓库 git clone <git 仓库地址>
  2. 当前项目目录执行 git submodule init,该命令会初始化本地配置文件
  3. 执行 git submodule update 检查该项目子模块所有的更新

另外 2和3可以直接简写为 git submodule update --init --recursive

image.png

如何更新 Git submodule

子模块修改后需要更新主仓库

主仓库和子模块的更新和正常使用 git项目一致,这里主要说明一下子模块的修改之后主仓库仍然需要提交更新之后的 submodule,提交到git记录里。

下图对子模块进行修改提交,注意git submodule 里指向的只是一个 commit SHA 值,需要 checkout 到你需要提交到的分支

image.png

之后需要再次提交主仓库的修改

image.png

子模块有更新同步到本地

主项目直接 git pull 即可(但是需要注意 submodule 的在一个修改后确定的的分支上)。

image.png

如何彻底删除 Git submodule

相当复杂如下所示:

  1. 移除目录 git rm --cache <git submodudle 所在目录>

  2. rm -rf <git submodudle 所在目录>

  3. 删除 .gitmodules 或者 编辑 .gitmodules 删除该文件里该 submodule 的记录

     ```
     [submodule "plugins/repoB"]
     path = plugins/repoB
     url = [email protected]:paddingme/repoB.git
     branch = dev
     ```
  4. 修改 ./git/config 中该submodule相关内容

    [core]
      repositoryformatversion = 0
      filemode = true
      bare = false
      logallrefupdates = true
      ignorecase = true
      precomposeunicode = true
      [remote "origin"]
              url = [email protected]:paddingme/repoA.git
              fetch = +refs/heads/*:refs/remotes/origin/*
      [branch "main"]
              remote = origin
              merge = refs/heads/main
      [submodule "plugins/repoB"] # 删除这里
              url = [email protected]:paddingme/repoB.git # 删除
              active = true # 删除
      ```
  5. 删除 .git 文件夹中的相关子模块文件 如rm -rf .git/modules/plugins/repoB/

  6. git add .&& commit

  7. 最后最好再 git submodule sync 下。

这里就不演示了,累了。

总结

如上,不得不说 git submodule 用起来有点复杂,有一定的学习成本,在使用 git submodule 时记住如下两条,会让情况变得好一些,再者就是常回来看看这篇文章情况可能还会更好一点。

  1. 常用 git status 查看当前目录状态
  2. 确认 submodule 是否在正确的分支上

References

题图: Git Submodule — Make it work