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