git subtree 管理项目子模块

使用场景

当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们可以使用git的subtree功能

常用命令

git subtree add --prefix=    --squash 添加子仓库
git subtree pull --prefix=   --squash 拉取更新子仓库
git subtree push --prefix=   推送修改到子仓库

如何使用

1. 创建带subtree的版本库

例如我们要构建如下结构的项目

project
    | --moduleA
    | --readme.txt

创建project版本库,并提交readme.txt文件

git init --bare project.git
git clone project.git project1
cd project1
echo "This is a project." > readme.txt
git add .
git commit -m "add readme.txt"
git push origin master
cd ..

创建moduleA版本库,并提交a.txt文件

git init --bare moduleA.git
git clone moduleA.git/ moduleA
cd moduleA
echo "This is a submodule" > a.txt
git add .
git commit -m "add a.txt"
git push origin master
cd ..

在project项目中引入子模块moduleA,并提交子模块信息

cd project1
git subtree add --prefix=moduleA ../moduleA.git/ master --squash
git status
git push origin master
cd ..

--prefix指明了存放子模块目录结构,../moduleA.git 是子模块的地址,--squash参数,就是把subtree的子项目更新记录合并,再合并到主项目中。详细的分析请参看[git subtree相关问题。最后,记得push更新信息到远端。

克隆带子模块的版本库

与submodule命令不同,subtree克隆命令非常简单

git clone project.git project2

subtree命令同时拉取父项目和子项目;而submodule需要先克隆父项目,然后用submodule init初始化,最后用submodule update来拉取子模块

推送修改到子模块

如果在project1仓库中对moduleA进行了修改,使用subtree push将修改推送到moduleA

cd project1/moduleA/
echo "This is b.txt" > b.txt
git add .
git commit -m "update moduleA:add b.txt"
git push origin master
git subtree push --prefix=moduleA/ ../moduleA.git master

git push将所有更新推送到父项目,git subtree push将更新推送到子项目

拉取子模块的更新

当子模块进行了更新,父项目使用git subtree pull来获取更新

cd moduleA
echo "This is c.txt" > c.txt
git add .
git commit -m "add c.txt"
git push origin master
cd ../project1
git subtree pull --prefix=moduleA/ ../moduleA.git master --squash

删除子模块

删除使用subtree管理的子模块非常简单,只要将子模块看成是普通文件进行删除即可

cd project1
git rm -rf moduelA
git commit -m "remote moduleA"
git push origin master

简化版命令

子模块的地址通常比较长,不容易记忆,这里我们可以将子仓库的地址作为一个remote,方便记忆

git remote add moduleA ../moduleA.git

然后可以简化subtree命令

git subtree add --prefix=moduleA moduleA master --squash
git subtree pull --prefix=moduleA moduleA master --squash
git subtree push --prefix=moduleA moduleA master

Q&A

Q:如何修改子模块存放的目录
A:对--prefix进行修改即可,例如可以使用

git subtree add --prefix=sub/moduleA ../moduleA.git/ master --squash

来得到如下目录结构:

project
    | --sub
        |--moduleA
    | --readme.txt

Q:subtreesubmodule的不同之处?
A: 网络上很多讨论,例如 Differences between git submodule and subtree和浅谈「用 git submodule 还是 git subtree」?
,正如这些讨论中所说的那样"submodule is link, subtree is copy"是最本质的区别。更具体的优劣对比,参考下面的表格

/ subtree submodule 对比结果
远程仓库占用空间 子模块copy,占用较大空间 只是引用,基本不占空间 使用submodule的远程仓库占用空间较小,略优
本地仓库占用空间 会下载整个项目 可根据下载,但基本都要全部下载 所有模块基本都要下载,二者差异不大
克隆仓库 克隆马上可用 克隆后所有模块为空,需要注册和更新,更新后还要切分支 submodule步骤多,subtree占优
更新本地仓库 所有子模块需要单独更细 更新后所有子模块指向最后一次提交,可能需要切回分支,所有模块可用一行命令更新 subtree虽然要手动对子模块一个一个更新,但是更新后就可用,submodule需要切回分支,对比下subtree比较合适
提交本地修改 所有子模块单独更新,指令较复杂 只关心子模块即可,所有操作与普通git项目相同 submodule优秀一丢丢

Q:使用subtree或者submodule有什么坑需要注意的?
A:请参看Git submodule的坑和git submoudle vs git subtree

参考

  • git子模块使用之git submodule与 git subtree比较
  • Git submodule的坑
  • git submoudle vs git subtree
  • git subtree教程
  • 浅谈「用 git submodule 还是 git subtree」?

你可能感兴趣的:(git,git,subtree)