git之submodule

当一个项目很大很复杂时,可以将项目分为几个模块分别进行管理;或者,当一个项目引用第三方开源代码,可以将这些第三方开源代码单独进行管理,这样做是为了代码隔离,方便项目维护。这时可以使用git的submodule功能,git submodule允许你将一个 git 仓库作为另一个 git 仓库的子目录。

git submodule用于多模块(仓库)管理,其父项目与子项目提交是分开的,父项目提交只包含子项目的信息,而不会包括子项目的代码,子项目使用独立的commit、push、pull操作。

简单来说:父项目git仓库管理父项目内容和子项目信息;子项目git仓库管理子项目内容。

常用命令:

git submodule add    # 添加子模块
git submodule init   # 初始化子模块
git submodule update # 更新子模块: 

git clone --recursive                     # 递归的方式克隆整个项目: 
git submodule foreach git pull            # 拉取所有子模块
git submodule foreach git checkout master # 所有子模块切到master分支

1 添加、同步子模块

这里通过一个示例来展示git submodule的使用。

1.1 添加一个模块

环境准备:

首先需要准备一个父项目与一个子项目。详细步骤见参考3《如何将本地代码推送至github》

  • 在github上新建一个父项目 submodule_main;并在本地新建工程,与github库绑定
mkdir submodule_main
cd submodule_main
echo "## submodule_main" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:sz-ok/submodule_main.git
git push -u origin main
  • 同样,在github上新建一个子项目submodule_subdir;并在本地新建工程,与github库绑定
mkdir submodule_subdir
cd submodule_subdir
echo "## submodule_subdir" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:sz-ok/submodule_subdir.git
git push -u origin main

这样,我们已经有了父项目submodule_main与子项目submodule_subdir,然后我们可以进行添加子模块的操作。

添加子模块:

git clone git@github.com:sz-ok/submodule_main.git         # clone 父项目
cd submodule_main/                                        # 进入父项目目录
git submodule add git@github.com:sz-ok/submodule_subdir.git #在主项目中添加子项目

这时项目中会多出submodule_subdir文件夹,是独立的子项目。整个项目包括了多个.git仓,且主项目目录下会多一个.gitmodules文件。

然后,在主项目目录下查看状态:

submodule_main$ git status
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   .gitmodules
	new file:   submodule_subdir

可见在添加子模块后,主项目下需要将子项目信息提交一次,提交后,在主项目仓库中,会显示出子模块文件夹,并附带其所在仓库的版本号,如:submodule_subdir @ abcd1234。

git add -u
git commit -m "add submodule"
git push    # 因为在建库时用了git push -u 所以后面push时可以直接git push

最终形成的目录结构如下(以下展示局部):

submodule_main$ tree -a -L 3
submodule_main
├── .git          # 父项目仓库
│   ├── branches
│   ├── config
│   ├── description
│   ├── HEAD
│   ├── hooks
│   ├── index
│   ├── info
│   ├── logs
│   ├── modules   # 管理子项目的modules
│   │   └── submodule_subdir 
│   ├── objects
│   ├── packed-refs
│   └── refs
├── .gitmodules   # 管理子项目的modules
├── README.md
└── submodule_subdir
    ├── .git         # 子项目仓库
    └── README.md

其中.gitmodules用来管理子模块,内容如下:

submodule_main$ cat .gitmodules
[submodule "submodule_subdir"]
        path = submodule_subdir
        url = git@github.com:sz-ok/submodule_subdir.git

1.2 clone已经存在的多仓库项目

如果我们需要从库上clone一个多仓库的项目。

方法1:

git clone git@github.com:sz-ok/submodule_main.git # 单独使用 git clone 命令是不会拉取到子项目的代码的
cd submodule_main/
git submodule init   # 只用执行一次,后续同步只需执行git submodule update
git submodule update # 更新子模块

这样就可以clone上节多仓库的工程。(不过示例中仅有一个模块,不能充分体现git submodule的优势,如果子模块非常多也是同样操作,不需要一个个pull库,然后组织在一起。)

方法2:

组合命令:

git clone git@github.com:sz-ok/submodule_main.git # 单独使用 git clone 命令是不会拉取到子项目的代码的
cd submodule_main/
git submodule update --init --recursive

方法3:

git clone时带上--recursive参数。

git clone git@github.com:sz-ok/submodule_main.git --recursive  # 递归的方式克隆整个项目

2 子模块库修改及提交

由于:父项目git仓库管理父项目内容和子项目信息;子项目git仓库管理子项目内容。

所以:

  • 父项目中的内容有改动,还是正常的git add, git commit, git push操作

  • 子项目中内容有改动时,同样需要git add, git commit, git push操作,然后父项目也要提交一次改动(因为子项目信息有改动)

父项目通过git diff并不能直接看到子项目的修改,如果需要查看,可在父目录下执行

git diff --submodule

3 模块的删除

删除子模块稍微比较复杂,还是以上述例子为例。

git rm --cached submodule_subdir
rm -rf submodule_subdir
vi .gitmodules # 只删除此模块信息
vim .git/config

进行上述操作后,需要在父目录下进行一次提交。

4 模块的分支管理

当clone包换submodule的项目时,主项目获取到的是子项目的commit id,所以clone之后子项目不在任何分支上。主项目执行 git submodule update 也不会更新,此时需要从主项目主动进入子项目执行 git pull 主动拉取新版代码,然后提交,更新子项目的commit id。如果要在主项目开发子模块,建议将子项目切到master分支进行提交。当主项目 clone 后,也可以使用 foreach 命令批量切换到 master 分支进行更新。

若一个项目中有多个子模块需要执行相同的操作,每次切换到对应的目录挨个执行效率太低,此时可以使用 git submodule foreach

类似:

git submodule foreach git checkout master
git submodule foreach git pull

参考:

  1. 使用Jenkins + git submodule 实现自动化编译,解决代码安全性问题
  2. Git Submodule管理项目子模块
  3. 如何将本地代码推送至github
  4. 公共模块管理之 Git Submodule 使用总结
posted @ 2022-09-07 22:46  sureZ_ok  阅读(753)  评论(0编辑  收藏  举报