多项目共享代码之——git subtree

需求

多个项目之间共享代码。
背景是前后端之间有一些protoc代码需要共享,避免互相发送文件(像某广东大厂这么山寨)。
由于protoc文件一般很小,因此首先考虑使用git subtree来建立子项目。

如果需要共享的部分占的存储空间很大(比如是一个超大的分词字典,则应该考虑git submodule)。

WHY: 为什么选择git substree

优点

简单、不容易出错
只有用到了这个子目录、子仓库的人才会需要使用git subtree相关命令去更新代码;也就是对于其他模块的开发人员,这就是一个普通目录,完全无感知,对无关人员完全透明。

劣势

性能
由于git substree本质上是跟踪了子仓库的所有文件来实现的,因此如果子仓库的存储空间占用很大,父仓库的git性能就会受到影响。(这个时候就需要考虑用别的办法了,比如从外部存储读取、或者用git submodule。)

原理

git subtree:

本质上是通过分支合并的方法模拟了一个子仓库,对于父仓库来说其实相当于从头到尾只有一个git。
首先git fetch就可以拉取任意git地址的代码,所以先用git fetch拉到某个目录,然后通过分支合并的方式把它们合并到当前分支。
因此本质上会跟踪子仓库所有文件。存储开销比较大。适用于子仓库全是纯代码的情况。

git subtree是由第三方开发者贡献的脚本,用git底层命令封装出来的。
从v1.5.2开始,git新增并推荐使用这个功能来管理子项目。

git submodule:

本质上父仓库只记录子仓库的commit-id,因此存储开销很小。但是缺点就是直接git clone的时候只会拉父仓库的代码,子仓库是空的,需要每个开发人员都主动拉子仓库代码,或者用递归的参数去拉。开发过程中出错的概率很高、比较繁琐,除非万不得已最好别用。

HOW: git subtree使用

首先新建一个git项目,补充.gitignore文件。
然后在原有的项目中通过以下命令来引入该项目到某个子目录(不需要预先创建子目录):

1
2
3
4
5
6
# 首次下载
git remote add -f <子仓库名> <子仓库地址>
git subtree add --prefix=<子目录名> <子仓库名> <分支> --squash
git fetch <远程仓库名> <分支>
git subtree pull --prefix=<子目录名> <远程仓库名> <分支> --squash
# git push review

其中的<分支>指的是子项目的分支。
以上前4个命令对应的操作就是:
1.给远程的某个xxx.git地址取个别名记录下来;
2.创建一个子目录专门跟踪子仓库;
3.拉取子仓库的某分支的代码;
4.把拉取的代码放到子目录。
建立关联以后,以后如果想要pull子项目代码,就只需要执行以下几步:

1
2
3
4
# 非首次下载
git fetch <远程仓库名> <分支>
git subtree pull --prefix=<子目录名> <远程仓库名> <分支> --squash
# git push review

以上就是一般情况下使用git subtree所需的所有命令了,非常得简单,新命令其实也只有两个git subtree命令。

这里大家可能会疑惑为什么没有提到给子仓库提交\push的命令,
其实命令是有的,但是没有必要在父仓库里提交子仓库的代码;
如果想更新子仓库的代码,直接随便找个目录git clone,git add,git commit, git push就行了,没有必要多记1个非必要的命令。
不过如果只是出于收藏爱好,可以收藏一下这个非必要的命令:

1
git subtree push --prefix=<子目录名> <远程仓库名> 分支

参考资料

https://my.oschina.net/jellypie/blog/487619
https://zhuanlan.zhihu.com/p/100214931

推荐文章