服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

git submodule 和 git subtree,你会选择哪个来管理子项目?

日期: 来源:神光的编程秘籍收集编辑:神说要有光zxg

如果想在一个项目中用另一个项目的代码,你会怎么做呢?

有同学说,可以发一个 npm 包呀,然后在另一个项目里引入。

这样是可以,但是如果经常需要改动它的源码呢?这样频繁发包就很麻烦。

那可以用 monorepo 的形式来组织呀,也就是一个项目下包含多个包,它们之间可以相互依赖。

这样确实可以频繁改动源码,然后另一个包里就直接可用了。

但如果这个包是一个独立的 git 仓库,我希望它虽然在另一个项目里用了,但要保留 git 仓库的独立性呢?

这种就可以用 git submodule 或者 git subtree 了。这俩都实现了一个 git 项目里引入了另一个 git 项目的功能。

那 submodule 和 subtree 都能做这个,它俩有什么区别呢?我该用哪个好呢?

这篇文章我们就来详细对比下 git submodule 还有 git subtree。

首先我们准备这样一个 git 项目:

3 个 commit,每个文件一个 commit。

然后在另一个项目里引入:

该怎么做呢?

我们先用 git submodule 的方式:

执行

git submodule add git@github.com:QuarkGluonPlasma/git-research-child.git child

这个命令就是添加这个 git 项目到 child 目录下:

然后我们再在 child 目录下再添加一个 git submodule:

cd child
git submodule add git@github.com:QuarkGluonPlasma/git-research-child.git child2

现在就是两级 git submodule 了:

在 .gitmodules 里记录着它的 url 和保存的 path:

前面说 submodule 能保留独立性,怎么看出来的呢?

首先,它有独立的 .git 目录,代表是单独 git 项目。

虽然这个 .git 目录是放在根 git 项目的 .git 下的:

这样就保证了它们依然可以独立的 pull 和 push。

比如我在 child 里加了一个 444.md 的文件:

你 git status 只能看到它提示了 submodule 有内容变动,但是根本不会管有什么变动。

你需要进入这个目录执行 git add、git commit、git push 才行。

也就是它依然是独立的项目,父项目只是记录了它关联的 commit id 是啥。

可以看到,子项目可以正常 push 成功。

这时候在 child 目录下执行 git status 就可以看到没有变动了:

但这时候你回到父级目录可以看到提示 submodule 有新的 commit:

我们新生成一个 commit 来保存这次变更:

这就是 submodule 的独立性,你可以在这个目录下单独执行 pull、push,单独管理变更,父项目只是记录关联的 commit 的变化。

那如果别人 clone 下这个项目来,还有这个 submodule 么?

我们 clone 下试试:

git clone git@github.com:QuarkGluonPlasma/git-research.git git-research-2

我把这个项目 clone 下来:

可以看到确实有 child 这个目录,但是没内容。

这是因为它需要单独初始化一下并更新下代码:

执行

git submodule init
git submodule update

或者执行

git submodule update --init

就可以看到代码被拉下来了:

但只有一层,如果想递归的 init 和 update,可以这样:

git submodule update --init --recursive

这样它就会把每一层 submodule 都拉下来:

这样就完整下载了整个项目的代码。

当然,这一步可以提前到 git clone,也就是执行:

git clone --recursive-submodules xxx

这样就不用单独 git submodule init 和 git submodule update 了。

小结下 git submodule 的用法:

  • 通过 git submodule add 在一个项目目录下添加另一个 git 项目作为 submodule

  • submodule 下可以单独 pull、push、add、commit 等

  • 父项目只是记录了 gitmodules 的 url 和它最新的 commit,并不管具体内容是什么

  • submodule 可以多层嵌套

  • git clone 的时候可以 --recursive-submodules 来递归初始化 submodules,或者单独执行 git submodule init 和 git submodule update

可以体会到啥叫复用子项目代码的同时保留项目的独立性了么?

然后我们再来试试 git subtree:

还是这样一个项目:

我们用 subtree 的命令添加子项目:

git subtree add --prefix=child git@github.com:QuarkGluonPlasma/git-research-child.git main

这样和 submodule 有什么区别呢?

不知道你有没有发现,child 目录下是没有 .git 的,这代码它不是一个单独的 git 项目,只是一个普通目录:

所以你在这个目录下的任何改动都可以被检测到:

可以和整个项目一起 git add、commit、push 等。

不过 subtree 的方式在创建目录的时候会生成一个 commit:

那这样都作为一个普通目录了,这个子项目还独立么?还能单独 pull 和 push 么?

可以的!

虽然没有单独的 .git 目录,但它依然有独立性。你可以通过 subtree 的命令来 pull 和 push 它的代码:

比如我们先试试 pull。

我在 git-search-child 这个项目下加两个 commit:

加了 555、666 这俩 commit。

然后我在项目下执行 git subtree pull:

git subtree pull --prefix=child git@github.com:QuarkGluonPlasma/git-research-child.git main

这样子项目的最新改动就拉下来了:

所以说 subtree 虽然把它作为普通目录来管理了,但它依然保留着独立 pull 和 push 到单独项目的能力!

上面的 url 如果你觉得敲起来麻烦,可以放到 git remote 里来管理:

git remote add child git@github.com:QuarkGluonPlasma/git-research-child.git

这样就可以只写它的名字了:

这样 pull,会生成 3 个 commit:

刚拉下来的 555、666 的 commit,还有一个 merge commit。

你也可以加个 --squash 来合并:

git subtree pull --prefix=child child main --squash

(这个 child 是我们前面添加的 git remote)

这样就只有一个合并后的 commit,一个 merge commit 了。这就是 --squash 的作用:

再来试下独立的 push。

这样就把它 push 上去了。

注意,这里可不是整个项目的 push,而是把那个子项目目录的改动 push 到了子项目里去。

另一个项目里就可以把它拉下来:

那问题来了,不是都没有 .git 目录了么?

那 subtree 是怎么知道哪些 commit 是新的,是属于这个子项目的呢?

还记得 subtree add 的时候单独生成了一个 commit 么?

git 会遍历 git log,直到找到这个 commit,然后把之间的 commit 里涉及到那个目录的改动摘出来,单独 push 到子项目。

因为有个遍历 commit 的过程,所以这一步可能会比较慢。

当然也有优化的方式,当 commit 多的时候,你可以执行:

git subtree split --prefix=child --rejoin

这样会单独生成一个这样的 commit:

因为 subtree push 的时候会从上往下找 commit,直到找到这样的 commit 结束。

所以 split 命令就可以指定找到哪个 commit,之前的就不找了,从而优化性能。

最后,git submodule 在 clone 的时候需要单独拉一下子项目代码,那 git subtree 呢?

我们试试:

git clone git@github.com:QuarkGluonPlasma/git-research.git git-research-3

可以看到,拉下来的就是全部的代码:

也就是说它真的就是个普通目录,只不过可以单独的作为子项目 pull 和 push 而已。

这就 git subtree 的使用方式。

小结一下:

  • git subtree add 可以在一个目录下添加另一个子项目
  • 子项目目录和别的目录没有区别,目录下改动会被 git 检测到
  • 可以用 git subtree pull 和 git subtree push 单独提交和拉取子项目代码
  • git subtree pull 加一个 --squash 可以合并拉下来的 commit
  • add 的时候会创建一个 commit,这是 push 的时候搜索 commit 的终点,你也可以用 git subtree split --rejoin 来单独生成一个这样的 commit

还有一点要注意,我用的 url 都是 git@github.com:QuarkGluonPlasma/git-research-child.git 这种,而不是 https://github.com/QuarkGluonPlasma/git-research-child

因为 github 现在 https 的方式需要输入用户名密码,而且已经被 github 禁掉了,这会导致子项目pull 和 push失败,所以统一用 ssh 的方式。

总结

当你想一个项目加入到另一个项目里来复用,并且还有保持这个项目可以作为独立 git 仓库管理的时候,就可以用 git submodule 或者 git subtree 了。

git submodule 会把子项目作为独立 git 仓库,你可以在这个目录下 pull、push、add、commit,父项目只记录着关联的 commit 是啥,并不关心子项目的具体变动。

git subtree 则是把子项目作为普通目录来管理,和别的文件没啥区别,都可以 add、commit 等。只不过依然保留了这个目录下的改动单独 pull、push 到子项目 git 仓库的能力。

这两种方式都可以复用项目代码的同时,保留子项目独立性。

不过 submodule 的方式耦合比较低,你能感觉出来它就是一个独立的 git 项目,你需要单独操作。

subtree 的方式,你根本感觉不到子项目的存在,它彻底融入了父项目。只是你依然可以单独的对它 pull、push 到子项目仓库。

我个人更喜欢 subtree 的方式,它更无感一点。

你呢?管理 git 项目里的 git 项目,你会选择 git submodule 还是 git subtree 呢?

相关阅读

  • 每日速递 | 天赐材料2022年收入超224亿

  • 会议倒计时9天2023复合集流体产业峰会——跨越从0到1 开启变革时代 主办单位:高工锂电、高工产业研究院(GGII) 总冠名:诺德股份 峰会地点:深圳机场凯悦酒店 峰会时间:2023年3
  • 每日速递 | 亿纬锂能2022年营收同比上升115%

  • 会议倒计时8天2023复合集流体产业峰会——跨越从0到1 开启变革时代 主办单位:高工锂电、高工产业研究院(GGII) 总冠名:诺德股份 峰会地点:深圳机场凯悦酒店 峰会时间:2023年3
  • 概率论、遍历性与科学下注

  • 作者:Jimmy Cui来源:BEDROCK(ID:brpartners)赌场模型假如你有一百万,现在有一个投资机会D,有50%概率赚60%,也有50%的概率亏损40%,你要投资吗?(不考虑破产、清仓等任何限制条件)答案当然
  • 2023政府投融资如何破局?

  • 原创声明:本文作者是金融监管研究院 资深研究员 杨瑾;谢绝其他媒体、公众号、网站转载,欢迎个人微信转发。以下课程为金融监管研究院专业打造的政信业务课程:经历了俄乌战争、
  • 雪+雨夹雪!还有降温10℃!河北未来三天…

  • 注意!雨雪闪现!明后两天天气将会插播一段小插曲像明天白天邢台南部、邯郸有小雨或零星小雨明夜到17日张家口南部、保定西北部有小雪或零星雨夹雪衡水东部、邢台、邯郸阴有小雨
  • 突然宣布:取消免费!

  • 3月14日,腾讯会议官方发布公告称,将从2023年4月4日起调整免费版和会员版的多项服务功能,涉及会议规模、时长和会员价格等方面。其中,腾讯会议免费用户“300人不限时会议”使用权
  • 今晚24时起,停止!

  • 记者日前从石家庄市城管局获悉,按照《石家庄市供热用热条例》相关规定,石家庄市将于3月15日24时停止供暖,提醒广大市民注意做好停暖后的过渡。根据我省各地之前发布的公开信息
  • 肖某(男,58岁),被立案

  • 3月15日,记者从贵州省贵阳市公安局交警支队获悉,13日,贵阳市发生一起因酒后驾车引发的道路交通事故。一男子酒后驾驶奔驰轿车与出租车发生剐蹭,在现场查处过程中,该男子自称公安
  • 3月,到冰城来看雪

  • 阳春3月,大雪纷飞仿佛又回到了冬季14日晚至15日哈尔滨市持续降雪雪中的冰城银装素裹如同一个白色的童话世界在各景区市民和游客们在雪中拍照、玩耍感受降雪带来的快乐本文版

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 本周末起,价格上涨!

  • 西湖景区春季旅游旺季今天正式拉开序幕!依照相关部门规定,本周末起,景区价格浮动的政府定价停车场收费标准有所调整。3月15日——5月31日景区双休日 小型车收费标准调整3月15日
  • 河南四地市委书记调整

  • 陈向平任平顶山市委书记日前,中共河南省委决定:陈向平同志任中共平顶山市委委员、常委、书记;免去张雷明同志的中共平顶山市委书记、常委、委员职务。万正峰任濮阳市委书记3月1