0. 简介
在面对复杂系统时,所有的模块不可能同时开发在一个project下的,而更多的可能就是每个人开发不同的模块,并通过一个模块将这些模块都整合到一起,这时候submodule的作用就非常明显了。通过设置submodule可以轻易地对不同的模块完成整合。同时大部分现代软件项目都需要依赖于他人的工作,当别人已经实现了一个很好的解决方案,就不需要再浪费时间再去实现一遍。因此很多项目都会以库或模块的形式使用第三方代码。本文将对submodule进行详细的说明,并向大家展示如何使用submodule。
1. submodule定义
为了弄清楚为什么Git的submodule很有价值,让我们先看一个没有submodule的例子。当我们需要引用**第三方代码(比如开源库)**的时候,最简单的办法是从GitHub下载代码,然后将其保存到自己的项目中。虽然这么做可以很快解决问题,但这么做非常丑陋,原因如下:
- 通过强制将第三方代码复制到项目中,我们可以有效的将多个项目混合到一个项目中,而我们自己的项目和别人的项目(库)之间的界限开始变得模糊。
- 每当我们需要更新库代码时(也许是因为它的维护者提供了一个很棒的新特性或修复了一个讨厌的bug),我们都必须再次下载、复制和粘贴,这很快就变成了一个乏味的过程。
软件开发中“将不同的东西分开”的一般规则是有原因的。当然,在自己的项目中管理第三方代码也需要这样,而Git submodule的概念正是针对这些情况而设计的。
2. submodule操作
2.1 创建子模块
举一个典型的例子,假设我们想要向项目中添加一个第三方库,在我们获取任何代码之前,需要先创建一个单独的文件夹,作为第三方库存储的路径
mkdir -p SLAM/2d-slam
cd SLAM/2d-slam
现在,我们准备将一些第三方代码以submodule的方式注入到项目中
# 使用 ssh完成 submodule
#git submodule add git@github.com:Lcp1/cartographer-note.git
# 默认url路径更新
# git submodule add https://github.com/Lcp1/cartographer-note.git
# 对submodule完成重命名
git submodule add --name cartographer-note https://github.com/Lcp1/cartographer-note.git
当我们运行这个命令时,Git开始将repository作为submodule克隆到我们的项目中:
然后我们就可以看到在对应的路径下已经加到项目里了。与此同时在主项目的根文件夹中创建了一个新的.gitmodules
文件。
[submodule "2d-slam/cartographer-note"]
path = 2d-slam/cartographer-note
url = https://github.com/Lcp1/cartographer-note.git
.gitmodules文件是Git用来跟踪项目中的submodule的几个配置之一,另一个是.git/config
,它的结尾被添加了下面的配置:
[submodule "2d-slam/cartographer-note"]
active = true
url = https://github.com/Lcp1/cartographer-note.git
最后,Git还在内部的.git/modules
文件夹中保存了每个子模块的.git仓库的副本。当然你不需要记住所有这些技术细节。可以看到,Git submodule的内部维护是相当复杂的,因此请记住:千万不要手工修改Git子模块的配置!如果你想移动、删除或以其他方式操作子模块,请不要手动尝试!!!!在添加完submodule后,我们既可以向正常的项目一样push代码了。
2.2 子模块的下载
在上面的示例中,我们向现有的Git repository添加了一个新的submodule。但是,反过来,当我们需要克隆一个已经包含submodule的仓库时,又会怎么样呢?
如果我们执行普通的git clone <remote-URL>
,将会下载主项目,但任何submodule文件夹都是空的!这再次生动的证明了submodle文件是独立的,不包含在它们的父仓库中。
git submodule init
git submodule update
或者在这种情况下,要在克隆了父仓库之后填充submodule,可以简单地执行git submodule update --init --recursive
。不过更好的方法是在调用git clone时直接添加--recurse-submodules
选项。
git submodule update --init --recursive
2.3 子模块的更新
从父仓库进入到modules目录(这个目录是submodule生成的),调用”git pull origin master“
cd modules
git pull origin master
然后就可以看到代码已经被更新到父仓库了