文章目录
1. submodule功能
git 的 submodule 功能,提供了单独管理子模块并建立当前项目与子模块之间的依赖关系的功能。即通过子模块,可以将外部库作为自己项目的一部分来管理,而不必将其直接合并到主仓中。
2. 在主仓中添加子模块
2.1 git submodule add
git submodule add [url] [path]
# url : 子仓的地址
# path : 子模块在主仓中的路径,可选项,若不指定则默认使用子仓的仓库名作为路径
在添加的时候使用-b
参数,可以指定子模块的分支
git submodule add -b [branchName] [url] [path]
添加之后,进行提交:git commit -m "add submodule"
,表示引入某个子模块,提交后主仓中就会显示出子模块文件夹,并带上其所在仓库的版本号commit id。
主仓的变更
添加子模块后,主仓的变化:
# 添加
git submodule add -b main https://github.com/zjy-10000hours/proj-sub-1.git
首先是主仓中有了.gitmodules
文件:
[submodule "proj-sub-1"]
path = proj-sub-1
url = https://github.com/zjy-10000hours/proj-sub-1.git
branch = main
.git/
路径下也多出了内容:
.git/config
文件中,多了submodule的内容:
[submodule "proj-sub-1"]
url = https://github.com/zjy-10000hours/proj-sub-1.git
active = true
.git/module
路径下也多出了proj-sub-1
的目录;查看目录结构:
然后可以提交一次,表明主仓添加了子模块。远端代码仓就可看到主仓中多出了.gitmodules
文件和子模块路径proj-sub-1
:
此时子仓的版本号1ffe953
。
2.2 git submodule init / update
在主仓中添加submodule后,就可执行git submodule init
,对子模块进行初始化:
git submodule init .\proj-sub-1\
git submodule update .\proj-sub-1\
然后进入子模块路径下就可看见子模块的文件了。
关于初始化命令:
git submodule init
执行后,会初始化配置文件中的所有子模块,根据.gitmodules
文件中的信息设置子模块的url、路径等,但不会下载子模块的内容,仅做初始化。
2.3 拉取带子模块的主仓内容
若要拉取的主仓本身就添加有submodule,此时在本地执行git clone [主仓的url]
,在本地不会自动拉取子仓的内容:
手动初始化更新:
git submodule update --init .\proj-sub-1\
若想在拉取主仓代码的同时拉取子仓的内容,加上参数--recurse-submodules
即可:
git clone [主仓的url] --recurse-submodules
3. 子模块的更新
主模块如何得知子模块的更新?
对于主模块,子模块的更新情况通常有以下三种:
- 场景1:在主模块下,修改了子仓的内容,子模块路径下就有了待提交的内容变动;
- 场景2:主模块的子模块路径下的内容发生了版本变化;
- 场景3:在主模块下,远端的子仓有人提交的新代码,导致子仓的版本号有更。
3.1 子模块下有内容变更
在本地修改了子仓的内容,并希望将修改推到远端子仓,但此时我自己在主仓下,如果想要提交子仓的修改,则需进入子模块路径下,按照正常的提交流程提交并push即可,此时就能将修改推到远端子仓。
提交、push完后,主仓的状态就是场景2,即主模块下子模块路径下的内容发生了版本变化。
3.2 子模块版本变更
# 进入子模块路径下,查看当前的HEAD指向的版本号
PS E:\workspace\tmp\proj-main-1\proj-sub-1> git branch
* (HEAD detached at 1ffe953)
main
# 修改子仓的内容,查看子仓状态,显示有未提交的文件
PS E:\workspace\tmp\proj-main-1\proj-sub-1> git status
HEAD detached at 1ffe953
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: sub_header_1.h
no changes added to commit (use "git add" and/or "git commit -a")
# 提交修改
# 此时HEAD指向新的提交
[detached HEAD 630f5ac] modify sub_header_1.h
# 查看主仓的状态
PS E:\workspace\tmp\proj-main-1> git status
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: proj-sub-1 (new commits)
Untracked files:
(use "git add <file>..." to include in what will be committed)
no changes added to commit (use "git add" and/or "git commit -a")
# 此时会主仓中会多出proj-sub-1.diff,其内容如下:
diff --git a/proj-sub-1 b/proj-sub-1
index 1ffe953..630f5ac 160000
--- a/proj-sub-1
+++ b/proj-sub-1
@@ -1 +1 @@
-Subproject commit 1ffe953cf784d2142cc9b476490a5beebdb652e7
+Subproject commit 630f5ac8671cd10c3feeefd287930698deae88cf # 可以看到子仓有新的提交
# 将其添加到主仓的代码提交中,表明子模块有更新
PS E:\workspace\tmp\proj-main-1> git commit -a -m "new commit of submodule"
[main e175aa5] new commit of submodule
# 将提交push到远端后,可看到子模块的版本号更新
3.3 子模块远程有更新
需要进入子模块路径下拉取最新的代码:
cd proj-sub-1
git pull origin main # 对应的分支
# 若主仓依赖的子模块太多,可以这样
git submodule foreach 'git pull origin main'
# foreach
for-each-ref
然后子模块目录下的代码版本就会发生变动,转到场景2进行提交。
3.4 git submodule update
git submodule update
在什么情况下才会更新子模块代码?
当主模块下的子模块路径下内容,和当前主模块记录的子模块版本不一致时,会参考后者进行更新。
比如说:(假设都在main分支下)主模块proj-main-1记录的子模块poj-sub-1的版本号是commit_1
,然后proj-main-1/proj-sub-1/下的内容有更新,版本号变成了commit_2
,此时执行git submodule update
,子模块的代码还是会切换到commit_1
版本.
4. 从主仓中移除子模块
卸载子模块:
git submodule deinit proj-sub # 卸载子模块,若加上参数--force,则子模块工作区内即使有本地修改,也会被移除
git rm proj-sub
执行git submodule deinit
命令的实际效果,是在.git/confg
中删除了如下内容:
[submodule "proj-sub"]
url = https://github.com/zjy/proj-sub
执行git rm proj-sub
的实际效果是移除了proj-sub文件夹,并自动在.gitmodules
中删除以下内容:
[submodule "proj-sub"]
path = proj-sub
url = https://github.com/zjy/proj-sub
此时,主项目中关于子模块proj-sub的信息已经基本删除,可以提交代码。