git 子模块使用方法
目录什么情况下使用子模块
如果想要在开发的项目中引入另外一个项目。那么除了直接将项目文件复制到主仓库目录下以外,还可以选择一种更优雅的方式,即本文所述的git子模块。这种方式可以将引入项目按照其本身的仓库状态进行管理。当引入项目有变更,不管是修复bug,还是更新功能,都可以方便的将其变更拉取到本地仓库中。
添加新的子模块
首先需要在主仓库中执行添加指令:
$ git submodule add https://github.com/Xsuns/xsuns_git_submodule_sub.git
拉取完毕后,主仓库将出现.gitmodules
文件和子仓库的目录(直接存入index中)。
$ git diff --cached
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..13fa722
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "xsuns_git_submodule_sub"]
+ path = xsuns_git_submodule_sub
+ url = https://github.com/Xsuns/xsuns_git_submodule_sub.git
diff --git a/xsuns_git_submodule_sub b/xsuns_git_submodule_sub
new file mode 160000
index 0000000..ba5bf6d
--- /dev/null
+++ b/xsuns_git_submodule_sub
@@ -0,0 +1 @@
+Subproject commit ba5bf6dad82173cded0d4fafe5e72c4a1643f611
其中记录的三行分别为子仓库的名称、本地目录和拉取地址,例子中的名称就是xsuns_git_submodule_sub
, 本地目录就是主仓库根目录下的./xsuns_git_submodule_sub
。
提交更改后,就完成了子模块的添加。
$ git commit -am '新增:增加子模块'
[main 2896730] 新增:增加子模块
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 xsuns_git_submodule_sub
$ git log -1
commit 28967303375194f32c92122b3e7e43dff2441d67 (HEAD -> main)
Author: Xsuns <[email protected]>
Date: Mon Apr 22 20:10:58 2024 +0800
新增:增加子模块
克隆含有子模块的仓库
对于含有子模块的仓库,需要使用递归克隆命令。
$ git clone --recurse-submodules https://github.com/Xsuns/xsuns_git_submodule_main.git
Cloning into 'xsuns_git_submodule_main'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
Submodule 'xsuns_git_submodule_sub' (https://github.com/Xsuns/xsuns_git_submodule_sub.git) registered for path 'xsuns_git_submodule_sub'
Cloning into 'xsuns_git_submodule_sub' ...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
Submodule path 'xsuns_git_submodule_sub': checked out 'ba5bf6dad82173cded0d4fafe5e72c4a1643f611'
如果忘记了,也无需删除原仓库,直接使用指令就可以递归更新。
ps. --recursive 可以递归更新子模块中嵌套的子模块,如果不使用此选项,会导致仅更新直接关联的子模块。
$ git submodule update --init --recursive
Submodule 'xsuns_git_submodule_sub' (https://github.com/Xsuns/xsuns_git_submodule_sub.git) registered for path 'xsuns_git_submodule_sub'
Cloning into 'xsuns_git_submodule_sub' ...
Submodule path 'xsuns_git_submodule_sub': checked out 'ba5bf6dad82173cded0d4fafe5e72c4a1643f611'
主仓库更新子模块
如果只想要同步子模块默认的最新分支,那么只需要以下指令即可。
ps. 如果想要更改默认子模块远程分支,可以在
.gitmodule
中子模块对应位置增加branch = target
。
$ git submodule update --remote
Submodule path 'xsuns_git_submodule_sub': checked out 'ed54345e540890f5ebd258327757de805f5e028c'
$ git diff --submodule
Submodule xsuns_git_submodule_sub ba5bf6d..ed54345:
> 修改:readme文档标题错误
同样地,如果要将子模块变更保存到主仓库中,需要在主仓库进行提交。
$ git commit -am '新增:更新子模块'
[main c057e0e] 新增:更新子模块
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log -p --submodule -1
commit c057e0e5dea6e369801c2fce168c62438a9e7c69 (HEAD -> main)
Author: Xsuns <[email protected]>
Date: Mon Apr 22 20:50:13 2024 +0800
新增:更新子模块
Submodule xsuns_git_submodule_sub ba5bf6d..ed54345:
> 修改:readme文档标题错误
如果你想更加自由,也可以进入子模块的目录中运行git fetch
和git merge
进行拉取。
拉取更新了子模块的主仓库
对于主仓库的协作者,当主仓库更新了子模块,仅仅使用git pull
是不够的,它仅能修改主仓库中记录的子仓库版本,不能自动检出对应的版本。
$ git pull
Updating 2896730..c057e0e
Fast-forward
xsuns_git_submodule_sub | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git status
On branch main
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: xsuns_git_submodule_sub (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
因此还需要如下指令。
$ git submodule update --init --recursive
Submodule path 'xsuns_git_submodule_sub': checked out 'ed54345e540890f5ebd258327757de805f5e028c'
ps.
init
可以在主仓库增加了新的子模块时自动初始化并拉取,recursive
则可以更新子模块的嵌套子模块。
还有一种特殊情况是,主仓库.gitmodules
中子模块的url发生了改变,你需要更新主仓库引用,可以在git submodule update
调用同步指令。
$ git submodule sync --recursive
Synchronizing submodule url for 'xsuns_git_submodule_sub'
$ git submodule update --init --recursive
ps. 同样地,如果你在本地修改了
.gitmodules
中的url,也要执行此同步指令
在子模块上工作
个人经验来说,不建议在开发主仓库的过程中,同步对子模块进行修改,特别是来自第三方的库。因为本地子模块改动如果无法推送到子模块仓库,会导致其他人拉取主仓库时无法拉取到子模块的修改。这时唯一的解决办法就只有对子模块仓库进行fork
,并修改子模块url
为fork
后的仓库,然后去维护此仓库。
但如果你一定要这样做,首先你需要进入子仓库中检出一个工作分支,因为在前几个章节的操作后,子模块将属于游离态,不属于任何分支。
$ git status
HEAD detached at ed54345
nothing to commit, working tree clean
$ git checkout main
Switched to branch 'main'
后续对子模块进行更新,需要加上选项--merge
或者--rebase
,如果忘记的话,子模块会重新变为游离态,此时只要在子模块目录下再次检出工作分支进行手动merge
或者rebase
即可。
$ git submodule update --remote --merge
Updating ba5bf6d..ed54345
Fast-forward
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Submodule path 'xsuns_git_submodule_sub': merged in 'ed54345e540890f5ebd258327757de805f5e028c'
如果你有权限将子模块推送到对应仓库,你可以在子模块目录下直接进行推送,然后在推送主仓库时使用选项--recurse-submodules
,将其设置为check
,这样主仓库推送时会进行检查,在子仓库改动未推送时推送失败。
$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:
xsuns_git_submodule_sub
Please try
git push --recurse-submodules=on-demand
or cd to the path and use
git push
to push them to a remote.
fatal: Aborting.
推送失败的提示中也有提到将选项--recurse-submodules
设置为on-demand
,git
将自动尝试推送子模块。
$ git push --recurse-submodules=on-demand
Pushing submodule 'xsuns_git_submodule_sub'
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 301 bytes | 301.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/Xsuns/xsuns_git_submodule_sub.git
ed54345..2631874 main -> main
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 32 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 271 bytes | 271.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/Xsuns/xsuns_git_submodule_main.git
c057e0e..6718be9 main -> main
如果你在本地修改了子模块,远程主仓库的子模块也被人修改了,即子模块历史出现分叉。此时git pull
拉取主仓库时将无法顺利合并.
$ git pull --recurse-submodules
Fetching submodule xsuns_git_submodule_sub
Failed to merge submodule xsuns_git_submodule_sub
CONFLICT (submodule): Merge conflict in xsuns_git_submodule_sub
Automatic merge failed; fix conflicts and then commit the result.
$ git diff
diff --cc xsuns_git_submodule_sub
index 7ab5f6c,9670894..0000000
--- a/xsuns_git_submodule_sub
+++ b/xsuns_git_submodule_sub
这时就需要进入子仓库去进行手动合并,首先要根据第二个SHA1
创建一个新的分支去合并。
$ cd xsuns_git_submodule_sub
$ git branch try-merge 9670894
$ git merge try-merge
Auto-merging readme.md
CONFLICT (content): Merge conflict in readme.md
Automatic merge failed; fix conflicts and then commit the result.
此时得到了一个一般的合并冲突,然后就按照常规方式解决即可
$ git commit -am '合并:保留所有更改'
[main b342081] 合并:保留所有更改
$ cd ..
$ git diff
diff --cc xsuns_git_submodule_sub
index 7ab5f6c,9670894..0000000
--- a/xsuns_git_submodule_sub
+++ b/xsuns_git_submodule_sub
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit 7ab5f6cd6823c28650eb6f4c50c0d41686ba6f7e
-Subproject commit 96708949bbc90b7b721880546ac6e82d500ac80a
++Subproject commit b342081a9666aab88e3141c115bb79c1894446b9
$ git commit -am '合并:上游更改'
[main 7385bba] 合并:上游更改
参考来源
[1] Scott Chacon, Ben Straub. Pro Git Book 2nd Edition
标签:submodule,sub,--,xsuns,git,模块,方法 From: https://www.cnblogs.com/xsuns/p/18151780