简介
submodule 用于在一个 git repo 中包含其它 git repo,内部的 git repo 被称为 submodule。submodule 的实现原理:
主仓库并不保存子仓库代码 ↓ 只保存子仓库的 commit SHA ↓ checkout 时再去子仓库仓库取对应 commit
因为它记录的是子仓库的 commit SHA,缺乏明确的版本管理,所以 submodule 并不是解决项目依赖的推荐方法。
{parent_repo}/.gitmodules
它告诉主仓库
- submodule 在哪里
- 从哪个 URL 拉取
- (可选) 使用那个 branch
[submodule "libs/lib"]
path = libs/lib
url = https://github.com/example/lib.git
branch = main
子仓库的 commit SHA 记录在主仓库的 git tree 里
添加或修改子仓库后,在主仓库 commit,其实就是在保存当前子仓库对应的 commit SHA。
查看 submodule commit SHA 的命令:git submodule status
$ git submodule status 3de8cf12908c4d0a55b0a0c309969e2514ab0532 submodules/blog (heads/main)
新添加的 submodule 是最新的 commit SHA,随着开发,通常需要依赖子仓库的某个 release (tag,例如 release/v1.2)。更新子仓库 commit SHA:
- 子仓库:
- git fetch –tags
- git checkout release/v1.2
- 主仓库:
- git add libs/lib
- git commit -m “Upgrade lib to v1.3.0”
主仓库的 commit 记录
git ls-tree HEAD
输出可能类似:
100644 blob abc123... .gitmodules 040000 tree def456... src 160000 commit 7f8e9d... libs/lib
160000 commit 7f8e9d... libs/lib 记录着 submodule 的 commit SHA。
160000= Git 特殊文件类型,表示 submodule7f8e9d...= submodule 对应的 commit SHAlibs/lib= submodule 路径
常用命令
添加 submodule
git submodule add https://github.com//rock rock
下载 submodule
普通 git clone 主仓库,不会 pull submodules 的内容。
添加 –cursive 在 git clone 时拉取所有内容。
git clone --recursive <project url>
或者在主仓库里,手动更新所有 submodules。
git submodule update --init --recursive
抽取 folder 为 独立 repo,并保留 commit history
比如 main-repo 里有 gui, server, tools 等 folder,如果想把 tools folder 独立成一个 git repo,并且保留 commit history。这样抽取出来的 tools repo 就可以共享给其它 project 了。
执行下面的命令后,当前 folder 就只包含 tools 里的内容,可以把它 push 到仓库里了。
git clone {main-repo-url}
cd main-repo
git filter-branch --subdirectory-filter tools -- --all
git remote set-url origin {tools-repo-url}
git push
总结
- 在选择 git submodule 时,想想有没有其它更好的方案。很多语言都有自己的 lib 管理工具,例如 Java maven,Node npm,Python pip 等。
- 不适合在主仓库里对子仓库修改,然后 push 回子仓库。
- submodule 的 commit SHA 更新后,其它人需要手动更新一下
git submodule update。