当前位置:   article > 正文

git subtree 管理项目子模块

git subtree

使用场景

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

常用命令

git subtree add --prefix=<prefix> <repository> <branch> <ref> --squash 添加子仓库
git subtree pull --prefix=<prefix> <repository> <branch> --squash 拉取更新子仓库
git subtree push --prefix=<prefix> <repository> <branch> 推送修改到子仓库
  • 1
  • 2
  • 3

如何使用

1. 创建带subtree的版本库

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

project
    | --moduleA
    | --readme.txt
  • 1
  • 2
  • 3

创建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 ..
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

创建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 ..
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

cd project1
git subtree add --prefix=moduleA ../moduleA.git/ master --squash
git status
git push origin master
cd ..
  • 1
  • 2
  • 3
  • 4
  • 5

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

克隆带子模块的版本库

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

git clone project.git project2
  • 1

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

删除子模块

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

cd project1
git rm -rf moduelA
git commit -m "remote moduleA"
git push origin master
  • 1
  • 2
  • 3
  • 4

简化版命令

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

git remote add moduleA ../moduleA.git
  • 1

然后可以简化subtree命令

git subtree add --prefix=moduleA moduleA master --squash
git subtree pull --prefix=moduleA moduleA master --squash
git subtree push --prefix=moduleA moduleA master
  • 1
  • 2
  • 3

Q&A

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

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

来得到如下目录结构:

project
    | --sub
        |--moduleA
    | --readme.txt
  • 1
  • 2
  • 3
  • 4

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

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

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

参考

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/861275
推荐阅读
相关标签
  

闽ICP备14008679号