Git Submodule 用法笔记

Version

git version 2.21.0

新增 submodule

1
2
# git submodule add https://github.com/theme-next/hexo-theme-next.git themes/next/
git submodule add <url> <folder>

如果出现 xxx already exists in the index 的提示,则给根据Issue with adding common code as git submodule: “already exists in the index” 里面的回答,执行 git rm -f --cached <folder> 后,在执行 git submodule add

如果这个仓库先前没有用过 submodule,那么 Git 会在目录下建立一个叫做 .gitmodules 的文件,这里记录了 remote repo 的 URL 和这个 submodule 在此目录的路径。执行此命令后 submodule 和 .gitmodules 会自动 staged,这个时候可以 commit 和 push。

更新 submodule

必须到个人的目录底下执行 git pull 去拉取 upstream 的代码,可是这样会比较安全;若要一次全部更新所有的 submodule,可以用 foreach 命令:

1
git submodule foreach --recursive git pull origin master

删除 submodule

本以为会有像是 git submodule rm 这样的命令,结果竟然没有,必须辛苦的一个一个手动移除,不知道不实现这个命令的考量是什么,希望未来的版本能把它加上去。

移除 submodule 有以下几个步骤要做,先把 submodule 目录从版本控制移除:

1
2
git rm --cached <folder>
rm -rf <folder>

再来是修改 .gitmodules 文件,把不用的 submodule 删掉,例如:

1
2
3
- [submodule "themes/next"]
- path = themes/next
- url = https://github.com/theme-next/hexo-theme-next.git

还要修改 .git/config 的內容,跟 .gitmodules 一样,把需要移除的 submodule 删掉,最后再 commit。

clone 时把 submodule 一起 clone 下来

执行 git clone 时 Git 不会自动把 submodule 一起 clone 下来,必须加上 --recursive 这个参数,这样可以连带 submodule 的 submodule 通通一起 clone 下来:

1
git clone --recursive <url>

如果已经 clone 才发现 submodule 是空的,可以用以下命令去 clone:

1
2
git submodule init
git submodule update --recursive

init 会在 .git/config 下注册 remote repo 的 URL 和 local path。或是合并成一行 git submodule update --init --recursive 也可以,如果 upstream 有人改过 .gitmodules,那本地好像也是用这个方法更新。

命令解释

  • git submodule init:根据 .gitmodules 的名称和 URL,将这些信息注册到 .git/config 内,可是把 .gitmodules 內不用的 submodule 移除,使用命令并没有办法自动删除 .git/config 的相关內容,必须手动刪除;

  • git submodule update:根据已注册(也就是 .git/config )的 submodule 进行更新,例如 clone 遗失的 submodule,也就是上一段讲的方法,所以执行这个命令前最好加上 --init

  • git submodule sync:如果 submodule 的 remote URL 有变动,可以在 .gitmodules 修正 URL,然后执行这个命令,便会将 submodule 的 remote URL 更正。