Git引用外部库的子目录

前言

之前做独立游戏的时候我们是用的SVN进行版本控制的,主要原因当然是除了我的其他所有人之前都没用过Git😂。。。

然后我自己做东西的话都是用Git的。关于Git和SVN之间的党争就不多说啥了,反正都一样用。不过我是发现SVN有个很好用的功能然而Git并不支持。。

正片

其实就是SVN的外链功能,具体来说就是SVN目录的svn:externals属性,用处就是在当前目录去引用到另外一个仓库的某个特定目录。

当然Git也有类似的功能也就是submodule,不过根据Git的设计,Git是不可以只检出某个代码仓库的某个子目录的,而是必须把整个代码库作为一个整体检出。当然,如果需求就是引用整个代码库,那submodule可以完美地解决问题。此时如果我想从外部的某个公共代码库引用某一个公共代码而不想把整个公共代码库全放到我的工程目录里,我是还没发现用Git怎么直接做到这一点。

在Google上翻了半天,算是找到了一个能暂时实现类似svn:externals的效果的一个变通方法吧(当然只是能用)。

具体做法

还是使用submodule功能(配合部分检出sparse-checkout),首先在git的根目录新建一个目录/submodules/,当然放到哪里都无所谓,主要是为了把所有有可能用到的子模块都统一整理到一起;然后在输入命令(详细的用法请参考Git文档:git help submodule):

1
$ git submodule add --name NAME URL submodules/NAME

其中NAME需要替换成代码库的名字(理论上可以随便取,不过为了方便还是用跟代码仓库一样的名字吧),URL需要替换成需要引入的外部代码仓库的地址如https://github.com/xxx/xxx.git

然后这项操作会把代码库中所有的文件都checkout出来,所以我们要进入submodules/NAME目录,把里面我们不需要的目录都删了。当然也可以先都删完,我们接下来配置一下,让git只checkout我们需要的部分。

  1. 修改代码库的.git/modules/刚才新加的模块/config文件,在[core]下面添加一行sparsecheckout = true
  2. .git/modules/刚才新加的模块/info/目录中新建空文件sparse-checkout(没有扩展名),把你在子模块中需要的每个子目录的路径(相对于子模块根目录)加到sparse-checkout里,每个路径一行
  3. 执行git submodule update,就会发现/submodules/刚才新加的模块/目录下已经只有刚才配置的路径了

接下来,可以通过软链接的方式把实际的目录引用到我们需要的地方,就可以实现类似Svn外链的效果了,比如说在Windows环境下,使用管理员权限打开cmd,输入:

1
2
cd git仓库的根目录
mklink -D lib/SUB_FOLDER submodules/SUB_MODULE/SUB_FOLDER

这样的话,就会在lib目录下建立子模块SUB_MODULESUB_FOLDER子目录的符号链接了。

总结

这个方法还是比较繁琐,尤其是当子模块的代码库很大的时候,clone全部文件可能会比较慢,就算不checkout不需要的文件,.git目录中对应的objects也不会变小。当然最好的解决办法还是尽量把目录分的细一些,我介绍的这种方法比较适用于需要的子目录是代码库最大的一个子目录,只是剥除了仓库的顶部几层目录。比如说,子模块的目录结构是这样的:

1
2
3
4
5
CoolLibrary
|- src/
|- test/
|- build/
|- ...

假如src目录占了仓库的大头,而我们仅仅需要引用src目录本身而不需要其他的辅助性质的东西,就可以用本文这种方法,只检出src目录并软链接到项目的特定目录(比如3rd/CoolLibrary之类的)。