引言

Git是广泛使用的版本管理工具,对于子模块或第三方模块可以这样管理:

  • submodule: 第三方模块
  • subtree: 子模块,大项目团队内部互相协作

第三方模块(submodule)

既然是第三方模块,自然这个模块基本上是由别人开发完成,而自己只是作为这个模块的使用者,不会和自己的项目代码互动协作。

比如为项目添加gtest作为第三方库:

$ git submodule add https://github.com/google/googletest.git ./third_party/googletest

or

$ git submodule add https://github.com/google/googletest.git ./third_party/

它会自动把gtest代码clone下来,但对于本地项目本身来说,只是添加一个第三方模块记录文件(.gitmodules)而已:

[submodule "third_party/googletest"]
    path = third_party/googletest
    url = https://github.com/google/googletest.git

保持本地项目和第三方模块之间的彼此独立, 后续拿到这个项目的时候自动获取依赖的第三方模块代码。

子模块(subtree)

https://www.atlassian.com/git/tutorials/git-subtree

如果随着项目变大,想将一些功能模块独立变成子项目或子模块。

比如某个人或团队只需要维护一个功能模块,而不需要去接触庞大的整个项目,那么把这个功能模块以子模块形式分享出去是比较好的。

如果只是想将一部分功能变成子模块,后续彼此隔离,不会互相更新,则可以这样:

$ cd project-dir/
$ git subtree split -P Test -b v-Test # 将Test目录及记录变成一个分支
$ git pull origin v-Test # 另建立项目pull该分支即可

但一般情况下,这个子项目是要和庞大的整个项目保持互动的,可能会一起维护子项目后续更新,则要换一种方式。

比如有目录Test,想将它独立变成一个子项目并保持原有所有相关历史记录,可以:

$ git remote add mod-Test git@github.com:LeslieZhu/mod-Test.git
$ git subtree push --prefix=sub/Test mod-Test master            # 推送该子项目相关更新

如果后续还会共同维护子项目,则可以:

$ git subtree pull --prefix=sub/Test mod-Test master            # 拉取子项目相关更新和详细记录
$ git subtree pull --prefix=sub/Test mod-Test master --squash   # 拉取子项目相关更新但所有记录合并为一条

$ git subtree push --prefix=sub/Test mod-Test master            # 推送该子项目相关更新

使用subtree方式不会在git中留下特殊记录文件,对于拿到这个项目的人来说,并不会知道还有子项目或父项目的存在,看到的只是一个实实在在的目录。

总结

第三方模块使用submodule,内部项目子模块使用subtree