Forver.微笑

面带微笑未必真的开心,但笑起的那一刻,心中的那些不开心的事已经不重要了~

0%

git submodule的用法

大型项目中常常由多人合作,项目中会有一些功能有专人维护,其他人员不需修改。在git中使用submodule功能可以不必关心他人维护的模块,大大提高开发效率。

为git仓库新增子module

项目中常常会用到其他人维护的模块,可采用如下方式新增子module。

添加子模块

1
git submodule add <url> <path> # 添加远程子module,-b branch 才会写入分支信息,而且参数必须固定在add后

执行git status会看到项目中多了一个.gitmodules文件
可以每增加一个子module,.gitmodules会增加一条内容:

1
2
3
4
[submodule "modulename"]
path = dir
url = https://github.com/xxx/xxx.git
branch = master

然后按git的工作流程将子module信息同步到远程仓库

更新子module仓库信息

1
2
3
4
[submodule "modulename"]
path = dir
url = https://github.com/xxx/xxx.git
branch = master

直接修改.gitmodules中子仓库的上述任意信息。
仓库的.git/config中相关信息不会被自动修改。需要执行这条命令更新。

1
git submodule sync

然后按git的工作流程将子module信息同步到远程仓库

下载子module

克隆项目后,默认子模块只有对应的空文件夹。需要在子项目中完成如下命令初始化和克隆子module

1
2
git submodule init
git submodule update # clone

或者

1
git submodule update --init --recursive

批量更新子module

1
git submodule foreach git pull

删除子module

1
git rm -rf --caches <path>

或者

1
git deinit <path>

指向完毕后还要删除.gitmodules的对应信息,并push相关修改到远程仓库同步

在主项目中提交子项目代码

在子项目目录修改代码按照普通的git工作流程后,回到主项目工作
指向git status会发现有一条修改记录

1
2
3
4
5
6
7
8
9
10
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: <path> (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

在主项目执行git submodule update后, 子仓库就更新到之前旧的版本了!但是无需担心,子项目push过了,远程仓库的代码不会丢失。
这时到git的网页上看主项目的仓库的目录,子目录显示为<path> @ 9397017,对比子仓库的提交记录,发现后面的多出的字符对应的是子仓库的某条提交记录的commitId。远程仓库的commitId还停留在子项目的上一版本。
也就是说,子仓库提交代码后还需要将新的commitId同步到主项目中去。否则,主项目永远无法获取最新的子项目的最新修改。
按如下步骤同步子项目的commitId,再到网页上就可以看到子项目的commitId更新了。 也不会出现子项目代码无法更新的问题了。

1
2
3
git add -u
git commit -m "update submodule commitId"
git push

将git仓库中的子目录submodule化

除了在项目中新增子module的情况。
小项目在开发的过程中规模也会越来越大,团队扩大,需要将原项目拆分成小项目将一些功能交由专门的人员去维护。

可以为每个子项目采取如下的步骤拆分项目
最好为每个目拆分

克隆原项目

1
git clone https://gitee.com/XXX/XXX.git path

进入项目目录执行

1
git remote rm origin

拆分子项目

比如原项目中有个子目录下Test的内容需要独立成一个子项目,执行

1
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter Test -- --all

执行完后会发现原项目录下的内容被替换为Test的内容,并且查看日志可以看到当前项目保留了和项目Test修改相关的提交记录

清理残留内容

执行如下命令,清理一些残留的内容,减少仓库体积

1
2
3
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --aggressive --prune=now

将子项目push到远程仓库

为子项目创建远程仓库后,执行

1
2
git remote add origin https://github.com/XXX/Test.git
git push -u origin master

将原项目的内容替换为子module

该操作在原项目的本地仓库中操作,操作前确保需要提交的内容已全部提交

1
2
3
4
5
6
7
8
9
10
11
12
# 删除原项目中的子module文件
rm -rf Test
git add .
git commit -m "删除Test"

# 将Test替换为子module,子module会自动clone到本地
git submodule add -b master https://gitee.com/XXX/Test.git Test

# 将子module的信息同步到远程仓库
git add .
git commit -m "submodule Test"
git push

参考:
如何把GIT仓库中的子目录submodule化