随着项目不断壮大,使用单一仓库管理的代码就显得有点重,事实上在项目中也的确存在一些比较独立的,可以划分成子模块/子项目的部分,这些子模块/子项目是可以独立于当前业务项目存在,并为其它项目服务。子模块/子项目就需要从当前的git仓库中划分出去,另开炉灶,放在另外的仓库中管理。但同时,当前的业务项目依然会对子项目存在着依赖,如果单纯将子项目划分出去,并重新将子项目的仓库clone下来,与业务项目放在一起,有可能就要修改当前本地的目录结构,当需要修改子项目时,也需要到子项目的目录中commit,略显不便。
而git的subtree功能就是为了应对这种场景诞生的。subtree是git v1.8.0后才有的功能,简而言之,它的主要功能就是将不同仓库的项目以我们自主的方式组织到一块,并允许业务项目与子项目间互相同样同步,互相合并。
下面简单描述一下配置过程。
添加
对于一个项目 Project_One,下面存放着两个文件README.md与a.txt,并有两个提交,如图
同样,存在另一个项目Project_Sec,目录及提交记录如下
现在我们需要将Project_Sec作为子项目引进到Project_One中,可以使用以下命令
1 | git remote add -f <子项目名> <子项目git路径> |
其中,f 的含义为在add后马上执行fetch,将远程子项目的提交拉取下来。
如:
1 | git remote add -f Project_Sec git@github.com:demonk/Project_Sec.git |
添加完成后就可以将将Project_Sec作为子项目引用到Project_One的项目路径下了。
1 | git subtree add --prefix=<需要放置子项目的目录名> <子项目名> <子项目分支> --squash |
其中,prefix指定了在主项目下放置子项目的目录名,子项目不能直接放置在主项目下,会干扰到主项目的.git记录。
–squash是可选参数,可以将子项目的所有改动合并成一次commit,否则需要拉取整个提交记录。
如:
1 | git subtree add --prefix=subproject Project_Sec master --squash |
就是将Project_Sec的master分支拉取后放到subproject目录下,Project_Sec是上一步add的时候指定的。此时,主项目目录下就有了subproject的目录,里面放的就是子项目的修改。
如此两步,就可以将不同仓库的子项目添加到主项目中了。此时Project_One的提交记录变成
可以看到多了两个提交,这两个就是用于合并subproject时自动提交的。
pull
在添加子项目后,假如子项目存在更新,就需要pull子项目,然后再与主项目进行合并,这几步subtree都帮我们做好了。
1 | git fetch <子项目名> <分支名> |
基本上与上面是一样的。
我们先在Project_Sec的master中中提交一个文件l.txt,然后回到Project_One中,执行
1 | git fetch Project_Sec master |
git会自动生成一个合并commit,提交后及当前目录如图:
可以看到,l.txt已经顺利地合并过来了,Project_One上也添加了一个合并提交。
push
一般来说,合并到主项目中的子项目同样也是实打实的文件,同样可以进行编辑操作,那修改完后的文件应该如何将其合并到主项目,并更新回子项目仓库呢?这点subtree也帮我们处理好了,push只需要一个命令。
1 | git subtree push --prefix=<子项目的目录名> <子项目名> <子项目分支> |
如我们在subproject下添加了一个s.txt的文件,在主项目中将s.txt添加追踪并生成 一个commit后,直接执行下在的命令,修改即会同步回Project_Sec的仓库当中。
1 | git subtree push --prefix=subproject Project_Sec master |
此时Project_One不一定也得push,当push后,两个项目其实就一致了。
总结
简单来说,subtree这个功能算不得上强大,但对于主/子项目合并这种场景还是挺有用的,说明白了,它其实就是打通了两个仓库间的同步,主的推给主的,子的推回给子的,主项目同样也会包含子项目的所有文件,但子项目可以保持自己的独立,方便就方便在这里。
根据commit来看,也可以将它们看作是跨仓库的分支合并,它们其实也是一个fast-forward,但对于开发者来说,这点怎么实现虽然不重要,但因为要敲比较长的特殊指令,着实有点烦;而且,假如子项目存在多分支,主项目需要根据实际情况切换的时候可能也会有问题,但总而言之,有总好过没,起码有这功能才可能选用不用。