23.3 在子模组中修改和子模组的更新

执行git submodule update更新出来的子模组,都以某个具体的提交版本进行检出。进入某个子模组目录,会发现其处于非跟踪状态(分离头指针状态)。


$cd/path/to/my/workspace/super-clone/lib/lib_a

$git branch

*(no branch)

master


显然这种情况下,如果修改lib/lib_a下的文件,提交就会丢失。下面介绍一下如何在检出的子模组中修改,以及如何更新子模组。

在子模组中切换到master分支(或其他想要修改的分支)后再进行修改。

(1)切换到master分支,然后在工作区做一些改动。


$cd/path/to/my/workspace/super-clone/lib/lib_a

$git checkout master

hack…


(2)执行提交。


$git commit


(3)查看状态,会看到相对于远程分支领先一个提交。


$git status

On branch master

Your branch is ahead of 'origin/master' by 1 commit.

#

nothing to commit(working directory clean)


在git status的状态输出中,可以看出新提交尚未推送到远程版本库。现在暂时不推送,看看在super版本库中执行git submodule update对子模组的影响,具体操作过程如下。

(4)先到super-clone版本库查看一下状态,可以看到子模组已修改,包含了更新的提交。


$cd/path/to/my/workspace/super-clone/

$git status

On branch master

Changed but not updated:

(use "git add<file>…" to update what will be committed)

(use "git checkout—<file>…" to discard changes in working directory)

#

modified:lib/lib_a(new commits)

#

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


(5)通过git submodule stauts命令可以看出lib/lib_a子模组指向了新的提交ID(前面有一个加号),而lib/lib_b子模组状态正常(提交ID前是一个空格,不是加号也不是减号)。


$git submodule status

+5dea2693e5574a6e3b3a59c6b0c68cb08b2c07e9 lib/lib_a(heads/master)

3b52a710068edc070e3a386a6efcbdf28bf1bed5 lib/lib_b(heads/master)


(6)这时如果不小心执行了一次git submodule update命令,会将lib/lib_a重新切换到旧的指向。


$git submodule update

Submodule path 'lib/lib_a':checked out '126b18153583d9bee4562f9af6b9706d2e104016'


(7)执行git submodule status命令查看子模组状态,可以看到lib/lib_a子模组被重置了。


$git submodule status

126b18153583d9bee4562f9af6b9706d2e104016 lib/lib_a(remotes/origin/HEAD)

3b52a710068edc070e3a386a6efcbdf28bf1bed5 lib/lib_b(heads/master)


那么刚才在lib/lib_a中的提交丢失了么?实际上因为已经提交到了master主线,因此提交没有丢失,但是如果有数据没有提交,就会造成未提交数据的丢失。

(1)进到lib/lib_a目录,看到工作区再一次进入分离头指针状态。


$cd lib/lib_a

$git branch

*(no branch)

master


(2)重新检出master分支找回之前的提交。


$git checkout master

Previous HEAD position was 126b181…add data for libA

Switched to branch 'master'

Your branch is ahead of 'origin/master' by 1 commit.


现在如果要将lib/lib_a目录下子模组的改动记录到父项目(super版本库)中,就需要在父项目中进行一次提交才能实现。

(1)进入父项目根目录查看状态。因为lib/lib_a的提交已经恢复,因此再次显示为有改动。


$cd/path/to/my/workspace/super-clone/

$git status-s

M lib/lib_a


(2)查看差异比较,会看到指向子模组的gitlink有改动。


$git diff

diff—git a/lib/lib_a b/lib/lib_a

index 126b181..5dea269 160000

—-a/lib/lib_a

+++b/lib/lib_a

@@-1+1@@

-Subproject commit 126b18153583d9bee4562f9af6b9706d2e104016

+Subproject commit 5dea2693e5574a6e3b3a59c6b0c68cb08b2c07e9


(3)将gitlink的改动添加到暂存区,然后提交。


$git add-u

$git commit-m "submodule lib/lib_a upgrade to new version."


此时先不要忙着推送,因为如果此时执行git push将super版本库推送到远程版本库,会引发一个问题。即推送后的远程super版本库的子模组lib/lib_a指向了一个新的提交,而该提交还在本地的lib/lib_a版本库(尚未向上游推送),这会导致其他人克隆super版本库和更新模组时因为找不到该子模组版本库相应的提交而出错。下面就是这类错误的信息:


fatal:reference is not a tree:5dea2693e5574a6e3b3a59c6b0c68cb08b2c07e9

Unable to checkout '5dea2693e5574a6e3b3a59c6b0c68cb08b2c07e9' in submodule path

'lib/lib_a'


为了避免这种可能性的发生,最好先推送lib/lib_a中的新提交,然后再向super版本库推送更新的子模组gitlink改动。即:

(1)先推送子模组。


$cd/path/to/my/workspace/super-clone/lib/lib_a

$git push


(2)再推送父版本库。


$cd/path/to/my/workspace/super-clone/

$git push