submodule 是很方便的功能,但在使用中有一些痛点,其中对我们项目困扰最大的就是游离分支了,昨天专门花时间研究了下,终于弄懂了,这里记录下来,希望能帮到大家。
submodule 的原理
在说产生原因之前,先说下其原理,否则不太好说清楚。
- 在主仓库里,只记录 submodule 的
commit id
,相当于一个指向 submodule 的指针(为了描述方便,我们给这个指针起个名字叫sptr
)。 - 子模块的分支是记录在
.gitmodules
里的,sptr
只记commit id
, 不记其他任何信息,如果要改子模块分支,可以使用git config -f .gitmodules submodule.xxx.branch master
命令。 - 在主仓库下执行
git submodule update --remote
等价于进入 submodule 目录内,然后执行git pull
, 这两个操作都会把 submodule 目录中的文件(同样为了描述的方便,我们给它命名为scode
)更新到最新,并且更新sptr
。 - 在主仓库执行
git pull
并不会更新scode
, 哪怕pull之后sptr
已经指向一个新的commit
了,只有执行git submodule update
, 才会更新scode
。 - 本地
sptr
产生变动后,把它push到origin, 这时其他人在拉代码时,都会更新sptr
, 但scode
是否更新,还要看他们是否执行了git submodule update
。
更详细的描述,请查看:7.11 Git 工具 - 子模块
产生原因
如果了解了以上5点,那产生原因就比较容易说清楚了。
简单来说,就是主仓库的sptr
指向一个你本地不存在的commit id
时,子模块就会进入游离分支。
举个例子,假如有个子模块 s1
, 有100次提交,为了方便,我们假设commit id
就是1~100这样的数字。
本来 sptr
指向100,也没人更新子模块,这时大家都相安无事,直到有一个人更新了子模块,并push了一个commit id
=101的提交,并且他还把sptr
更新到101并推到了主仓库的远端(origin).
这个时候,别人在主仓库下执行git pull
时,sptr
就会指向101,但是当git去子模块里找这个commit id
时,由于还没执行git submodule update --remote
, 根本就找不到101
这个提交,然后子模块就会进入detached HEAD 101
的状态,也就是进入到了游离分支。
解决办法
知道了原因,再解决起来就很容易了。
只要我们在执行主仓库的git pull
时,先执行一下git submodule update --remote
, 把子模块更到最新,这样所有的commit id
都有了。不管主仓库的sptr
指向哪个commit id
,我们都可以适应,也就不会进入游离分支了。
以上就是本文的所有内容,希望对大家有所帮助。
END