1 简介 为什么需要子模块?:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。
Git
子模块是一个独立的 Git
仓库,被嵌套在另一个 Git
仓库中。它允许在一个存储库中引用另一个存储库,并且可以使项目更加模块化、易于维护。子模块允许你将一个Git
仓库作为另一个 Git
仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
2 开始使用子模块 2.1 添加子模块 我们首先将一个已存在的 Git
仓库添加为正在工作的仓库的子模块,你可以通过在git submodule add
后面加上想要跟踪的项目的相对或绝对URL
来添加新的子模块。在本例中,我们将会添加一个名为DbConnector
的库。
1 2 3 4 5 6 7 $ git submodule add https: //github.com/chaconinc/DbConnector Cloning into 'DbConnector'... remote: Counting objects: 11, done. remote: Compressing objects: 100% (10/10), done. remote: Total 11 (delta 0), reused 11 (delta 0) Unpacking objects: 100% (11/11), done. Checking connectivity... done.
默认情况下,子模块会将子项目放到一个与仓库同名的目录中,本例中是 DbConnector
。 如果你想要放到其他地方,那么可以在命令结尾添加一个不同的路径。
如果这时运行git status
,你会注意到几件事。
1 2 3 4 5 6 7 $git statusOn branch master Your branch is up-to-date with 'origin/master' . Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: .gitmodules new file: DbConnector
首先应当注意到新的.gitmodules
文件。 该配置文件保存了项目 URL 与已经拉取的本地目录之间的映射:
1 2 3 [submodule "DbConnector" ] path = DbConnector url = https://github.com/chaconinc/DbConnector
如果有多个子模块,该文件中就会有多条记录。 要重点注意的是,该文件也像.gitignore
文件一样受到(通过)版本控制。 它会和该项目的其他部分一同被拉取推送。 这就是克隆该项目的人知道去哪获得子模块的原因。
你也可以根据自己的需要,通过在本地执行 git config submodule.DbConnector.url <私有URL>
来覆盖这个选项的值。
在 git status 输出中列出的另一个是项目文件夹记录。 如果你运行git diff
,会看到类似下面的信息
虽然 DbConnector 是工作目录中的一个子目录,但 Git 还是会将它视作一个子模块。当你不在那个目录中时,Git 并不会跟踪它的内容, 而是将它看作子模块仓库中的某个具体的提交。 如果你想看到更漂亮的差异输出,可以给 git diff 传递 —submodule 选项。
当你提交时,会看到类似下面的信息:
1 2 3 4 5 $ git commit -am 'added DbConnector module' [master fb9093c] added DbConnector module 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 DbConnector
注意 DbConnector 记录的 160000 模式。 这是 Git 中的一种特殊模式,它本质上意味着你是将一次提交记作一项目录记录的,而非将它记录成一个子目录或者一个文件。
最后,推送这些更改:
1 $ git push origin master
2.2 克隆含有子模块的项目 接下来我们将会克隆一个含有子模块的项目。 当你在克隆这样的项目时,默认会包含该子模块目录,但其中还没有任何文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $ git clone https://github.com/chaconinc/MainProject Cloning into 'MainProject' ... remote: Counting objects: 14, done . remote: Compressing objects: 100% (13/13), done . remote: Total 14 (delta 1), reused 13 (delta 0) Unpacking objects: 100% (14/14), done . Checking connectivity... done . $ cd MainProject $ ls -la total 16 drwxr-xr-x 9 schacon staff 306 Sep 17 15:21 . drwxr-xr-x 7 schacon staff 238 Sep 17 15:21 .. drwxr-xr-x 13 schacon staff 442 Sep 17 15:21 .git -rw-r--r-- 1 schacon staff 92 Sep 17 15:21 .gitmodules drwxr-xr-x 2 schacon staff 68 Sep 17 15:21 DbConnector -rw-r--r-- 1 schacon staff 756 Sep 17 15:21 Makefile drwxr-xr-x 3 schacon staff 102 Sep 17 15:21 includes drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 scripts drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 src $ cd DbConnector/ $ ls $
其中有 DbConnector 目录,不过是空的。 你必须运行两个命令:git submodule init
用来初始化本地配置文件,而git submodule update
则从该项目中抓取所有数据并检出父项目中列出的合适的提交。
1 2 3 4 5 6 7 8 9 10 11 12 $ git submodule init Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector' $ git submodule update Cloning into 'DbConnector' ... remote: Counting objects: 11, done . remote: Compressing objects: 100% (10/10), done . remote: Total 11 (delta 0), reused 11 (delta 0) Unpacking objects: 100% (11/11), done . Checking connectivity... done . Submodule path 'DbConnector' : checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
现在 DbConnector 子目录是处在和之前提交时相同的状态了。
不过还有更简单一点的方式。 如果给 git clone 命令传递 —recurse-submodules 选项,它就会自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ git clone --recurse-submodules https://github.com/chaconinc/MainProject Cloning into 'MainProject' ... remote: Counting objects: 14, done . remote: Compressing objects: 100% (13/13), done . remote: Total 14 (delta 1), reused 13 (delta 0) Unpacking objects: 100% (14/14), done . Checking connectivity... done . Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector' Cloning into 'DbConnector' ... remote: Counting objects: 11, done . remote: Compressing objects: 100% (10/10), done . remote: Total 11 (delta 0), reused 11 (delta 0) Unpacking objects: 100% (11/11), done . Checking connectivity... done . Submodule path 'DbConnector' : checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
如果你已经克隆了项目但忘记了--recurse-submodules
,那么可以运行git submodule update
--init
将git submodule init
和 git submodule update
合并成一步。如果还要初始化、抓取并检出 任何嵌套的子模块, 请使用简明的git submodule update --init --recursive
。
2.3 在包含子模块的项目上工作