【笔记】Git - 子模块 submodule

蔡晨
2023-12-01

子模块 submodule

官方 api

git clone <repository> --recursive                                       # 递归的方式克隆整个项目
git submodule [--quiet] add [<options>] [--] <repository> [<path>]       # 添加子模块
git submodule [--quiet] init [--] [<path>…​]                              # 初始化子模块
git submodule [--quiet] update [<options>] [--] [<path>…​]                # 更新子模块
git submodule [--quiet] foreach [--recursive] <command>                  # xx 所有子模块 (如: git submodule foreach git pull  拉取所有子模块)
git submodule [--quiet] status [--cached] [--recursive] [--] [<path>…​]
git submodule [--quiet] deinit [-f|--force] (--all|[--] <path>…​)
git submodule [--quiet] summary [<options>] [--] [<path>…​]
git submodule [--quiet] sync [--recursive] [--] [<path>…​]
git submodule [--quiet] absorbgitdirs [--] [<path>…​]

看完后其实也差不多明白了,比其他git命令多了个 submodule 关键字;

子模块添加

git submodule add git@github.com:LawssssCat/rime-aurora.git

当 add 了 submodule 后,仓库在当前目录会有个 .gitmodules 文件。它记录 submodule 的 path 和 url。

[submodule "rime-aurora"]
	path = rime-aurora
	url = url....

还有一处改动在 .git/config

[submodule "rime-aurora"]
        active = true
        url = url....

同时,.git/config 文件的内容,最下面有 submodule 的注册信息!

$ git config --list --local
...
submodule.libs/lib1.active=true
submodule.libs/lib1.url=url....

添加后,用 git status 查看改动,看到两个改动:

  • 其中 .gitmodules 指定 submodule 的主要信息,包括子模块的路径和地址信息;
  • rime-aurora (子模块名字) 指定了子模块的 commit id
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   .gitmodules
        new file:   rime-aurora

这里需要指出父项目的 git 并不会记录 submodule 的文件变动,它是按照commit id 指定 submodule 的 git header,所以 .gitmodules 和 rime-aurora (子模块名字) 这两项是需要提交到父项目的远程仓库的。

子模块查看

git submodule 

克隆项目时,同时克隆子模块

方法一: 先 clone 父项目,再初始化 submodule,最后更新 submodule。

初始化只需要做一次,之后每次只需要直接 update 就可以了,需要注意 submodule 默认是不在任何分支上的,它指向父项目存储的 submodule commit id。

git clone project.git project2
cd project2
git submodule init
git submodule update

方法二: 采用递归参数 –recursive

git clone project.git project3 --recursive

子模块更新

git submodule update
git submodule foreach git pull
git submodule foreach --recursive git submodule init 
git submodule foreach --recursive git submodule update

⚠️ 注意:

如果是子模块不是通过 add 添加,而是新拉的代码里面就有 .gitmodules 。这时候 .git/config 里是没有 submodule 的注册信息的,这时候需要先 init

git submodule init
git submodule update

子模块修改

修改子模块之后只对子模块的版本库产生影响,对父项目的版本库不会产生任何影响,如果父项目需要用到最新的子模块代码,我们需要更新父项目中 submodule commit id,默认的我们使用 git status 就可以看到父项目中 submodule commit id 已经改变了,我们只需要再次提交就可以了。

# 进入子项目
$ cd project1/lua
# 更新模块代码
$ git pull
# 回到主项目
$ cd ..
# 查看改变
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   lua
$ git diff
diff --git a/lua b/lua
index d61b0c6..c954db3 160000
--- a/lua
+++ b/lua
@@ -1 +1 @@
-Subproject commit d61b0c60287c38008d312ddd11724a15b1737f7b
+Subproject commit c954db39241a8b21d7b32b42b87a066b4708f969

子模块删除

网传不少野路子方法删除子模块,但是:

不要手动修改 git 配置!
不要手动修改 git 配置!
不要手动修改 git 配置!

官方的做法是

# 逆初始化模块,其中{MOD_NAME}为模块目录,执行后可发现模块目录被清空
$ git submodule deinit {MOD_NAME} 
# 删除.gitmodules中记录的模块信息(--cached选项清除.git/modules中的缓存)
# $ git rm --cached {MOD_NAME} 
$ git rm {MOD_NAME}
# 提交更改到代码库,可观察到'.gitmodules'内容发生变更
$ git commit -am "Remove a submodule." 

 说明:

  1. git submodule deinit {MOD_NAME} 是删除了 .git/config 中的内容
  2. git rm {MOD_NAME} 是删除了 工作空间 和 .gitmodules 的内容

子模块 url 更新

有时候遇到 git submodule 的 URL 不可用需要更新,或者太慢需要更新到最近的 mirror URL 上。这时候需要更新 子模块的 url。

  1. 编辑 .gitmodules 文件,修改为你想要的那个URL。
  2. 执行 git submodule sync --recursive 将修改更新到 .git/config
  3. 更新 git submodule update --init 生效
 类似资料: