假设有两个项目project1和project2代码仓库:

$ ls project1/
HEAD        branches    config      description hooks       info        objects     refs
$ ls project2/
HEAD        branches    config      description hooks       info        objects     refs

1. 从代码仓库clone开发库p1/p2

$git clone ../project1 p1
Cloning into 'p1'...
warning: You appear to have cloned an empty repository.
done.
$ git clone ../project2 p2
Cloning into 'p2'...
warning: You appear to have cloned an empty repository.
done.

2. 对p1/p2做一些改动并且push到原代码仓库

在p1中添加新文件file1并且push到远程库project1

$ touch file1
$ git add file1
$ git commit
[master (root-commit) 9132026] Init project 1 with file1
 1 file changed, 0 insertions(+), 0 deletions(-)
         create mode 100644 file1

在p2中添加新文件file2并且push到远程库project2

$ touch file2
$ git add file2
$ git commit
[master (root-commit) 0e07357] Init project2 with file2
 1 file changed, 0 insertions(+), 0 deletions(-)
         create mode 100644 file2

3. 在开发库p1代码库中添加submodule ‘project2’

使用submodule add命令添加submodule到当前git代码库中,执行完成后submodule代码也会被clone到对应的目标目录。

git submodule add <URL to submodule remote> <submodule local dir>

例如:

$ git submodule add ../../project2 submodule/p2

此时代码已经被拉到本地submodule目录下,查看一下submodule目录已经同步好project2的代码:

$ ls
file1     submodule
$ ls submodule/p2/
file2

在project1目录中多出一个’.gitmodules’文件,该文件包含submodule信息:

$ cat .gitmodules
[submodule "submodule/p2"]
        path = submodule/p2
        url = /Users/wangq/tmp/submodule/project2
$ git submodule
 0e0735740297cce3ef051c9c84d20d032d03311a submodule/p2 (heads/master)

这时候需要添加初始化一下这个submodule

git submodule init
git submodule update

初始化后在主代码库目录中可以查看到submodule相关的两个改动,这两个改动可以被commit。

$ git status
On 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:   submodule/p2
$ git commit
[master 5d40507] Create submodule inside p1's working repository
 2 files changed, 4 insertions(+)
         create mode 100644 .gitmodules
         create mode 160000 submodule/p2

4. 此时如果project2的开发人员更新了project2的代码,我们可以把最新的代码同步到submodule中

$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/wangq/tmp/submodule/project2
   0e07357..db4f02b  master     -> origin/master
Updating 0e07357..db4f02b
Fast-forward
 file2 | 1 +
 1 file changed, 1 insertion(+)

查看一下其他人的改动内容如下:

$ cat file2
This line is change from another's working reposiroty

5.在p1中的submodule对project2进行了修改后也可以把新的修改发不到project2的远程库,这样project2的开发人员可以同步到最新的代码。

在p1的submodule目录中对p2进行修改并本地提交,然后把submodule的修改推到project2远程库中:

$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 335 bytes | 111.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /Users/wangq/tmp/submodule/project2
   db4f02b..f600361  master -> master

这是project2的其他开发人员可以在自己的代码库中同步这部分修改内容:

$ git pull origin master
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/wangq/tmp/submodule/test/../project2
 * branch            master     -> FETCH_HEAD
   db4f02b..f600361  master     -> origin/master
Updating db4f02b..f600361
 Fast-forward
 file2 | 1 +
 1 file changed, 1 insertion(+)

查看修改内容:

$ cat file2
This line is change from another's working reposiroty
This line is chaneg from p1's submodule repository      <-- 这一行是p1开发人员增加的内容

使用中碰到的问题

Trap 1: “Server does not allow request for unadvertised object”

$ git submodule update --checkout
error: Server does not allow request for unadvertised object 55e720e9c4ca96ae1d1bde84a1db3a12c90b9700
Fetched in submodule path 'submodule/p2', but it did not contain 55e720e9c4ca96ae1d1bde84a1db3a12c90b9700. Direct fetching of that commit failed.
  • 原因:

出现这个问题的原因是在submodule中进行的修改虽然已经commit到了superproject中,甚至是push到了superproject的远程库,但是当另外一个人尝试把这个superproject抓下来并同步这个submodule中的修改时,如果submodule的改动并未push到其对应的remote库,那么就会出现这个问题,因为update尝试从sudmobule的远程库pull对应的改动(55e720e9c4ca96ae1d1bde84a1db3a12c90b9700),而这个改动并未被push到远程库,因此也就不存在。