git subtree 最佳实践

目录

  • 1背景

    • [1.1 痛点](#1.1 痛点 "#11-%E7%97%9B%E7%82%B9")

    • [1.2 解决思路](#1.2 解决思路 "#12-%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF")

    • [1.3 什么是git子仓库](#1.3 什么是git子仓库 "#13-%E4%BB%80%E4%B9%88%E6%98%AFgit%E5%AD%90%E4%BB%93%E5%BA%93")

    • [1.4 git的两种子仓库方案](#1.4 git的两种子仓库方案 "#14-git%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%AD%90%E4%BB%93%E5%BA%93%E6%96%B9%E6%A1%88")

    • [1.5 git subtree 对现有项目的影响](#1.5 git subtree 对现有项目的影响 "#15-git-subtree-%E5%AF%B9%E7%8E%B0%E6%9C%89%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%BD%B1%E5%93%8D")

  • 2方案设计

    • [2.1 创建子仓库](#2.1 创建子仓库 "#21-%E5%88%9B%E5%BB%BA%E5%AD%90%E4%BB%93%E5%BA%93")

    • [2.2 关联子仓库](#2.2 关联子仓库 "#22-%E5%85%B3%E8%81%94%E5%AD%90%E4%BB%93%E5%BA%93")

    • [2.3 拉取子仓库更新](#2.3 拉取子仓库更新 "#23-%E6%8B%89%E5%8F%96%E5%AD%90%E4%BB%93%E5%BA%93%E6%9B%B4%E6%96%B0")

    • [2.4 推送更改到子仓库](#2.4 推送更改到子仓库 "#24-%E6%8E%A8%E9%80%81%E6%9B%B4%E6%94%B9%E5%88%B0%E5%AD%90%E4%BB%93%E5%BA%93")

    • [2.5 细节](#2.5 细节 "#25-%E7%BB%86%E8%8A%82")

1背景

1.1 痛点

目前业务主要有A端和B端两个系统,这两个系统技术栈是完全相同的,许多功能也相同。所以在日常的开发过程中,产生了大量的重复工作,一个需求在A端完成后,还需要复制到B端,这样往往容易出现疏漏。

1.2 解决思路

实现代码复用目前,有下面两种方法:

  • 抽象成NPM包进行复用

  • 使用Git的子仓库对代码进行复用

由于本项目要实现业务代码复用,抽成 npm 包的方式就不太合适。

1.3 什么是git子仓库

通俗上的理解, 一个Git仓库下面放了多个其他的Git仓库,其他的Git仓库就是我们父级仓库的子仓库。

通过使用git子仓库将公共的组件抽离出来,实现在一端更改后,另一端通过git去合并代码,将我们从繁重的复制粘贴中解放出来。同时,可以在后续的需求中放入公共组件,通过增量的方式去应用这个技术,不会影响以前的代码。

1.4 git的两种子仓库方案

目前git实现子仓库有下面两种方案:

  1. git submodule。 tdesign 使用的就是这种方案。

  2. git subtree

两种方案的对比如下:

维度 subtree submodule 优劣对比
空间占用 subtree 在初始化 add 时,会将子仓库 copy 到父仓库中,并产生至少一次 merge 记录。所以会占用大量父仓库空间 submodule 在初始化 add 时,会在父仓库新建一个 .gitmodules 文件,用于保存子仓库的 commit hash 引用。所以不会占用父仓库空间 submodule 更优
clone subtree add 至父仓库之后,后续的 clone 操作与单一仓库操作相同 后续 clone 时 submodule 还需要 init/update 操作,且 submodule 子仓库有自己的分支。 流水线部署时需要更改配置。 subtree 更优
update 子仓库更新后,父仓库需要 subtree pull 操作,且命令行略长,需要指定 --prefix 参数。由于无法感知子仓库的存在,可能会产生 merge 冲突需要处理 子仓库更新后,父仓库需要 submodule update 操作。父仓库只需变动子仓库 hash 引用,不会出现冲突 submodule 更优
commit 父仓库直接提交父子仓库目录里的变动。若修改了子仓库的文件,则需要执行 subtree push 父子仓库的变动需要单独分别提交。且注意先提交子仓库再提交父仓库 subtree 更优

用一句话来描述 Git Subtree 的优势就是:

经由 Git Subtree 来维护的子项目代码,对于父项目来说是透明的,所有的开发人员看到的就是一个普通的目录,原来怎么做现在依旧那么做,只需要维护这个 Subtree 的人在合适的时候去做同步代码的操作。

1.5 git subtree 对现有项目的影响

使用git subtree 无需改变现有工程结构,可以只在新需求中使用它去复用代码,相当于它只是一个复制粘贴的工具。

2方案设计

2.1 创建子仓库

建立一个单独的git仓库命名为 common , 可以创建如下的目录结构:

javascript 复制代码
-common
  -utils 公共的工具函数
  -services 接口
  -components 公共的组件
  -hooks 公共的hooks

2.2 关联子仓库

然后在A端和B端添加common的远程仓库:

bash 复制代码
 git remote add common [common仓库地址]

建立父仓库和子仓库的依赖关系:

bash 复制代码
git subtree add --prefix=src/common common master

将common远程仓库的master分支拷贝到父仓库的 src/common 目录下, 这时在两个项目的src目录多一个 common 的文件夹,我们可以像一个本地目录一样去使用里面的代码。

--prefix 可以用 -P 来代替,见下文。

2.3 拉取子仓库更新

bash 复制代码
git subtree pull -P src/common common master

2.4 推送更改到子仓库

方法一 直接提交

bash 复制代码
git subtree push -P src/common common master

subtree push实际上是遍历本工程每一次提交,把提交文件涉及到subtree目录的挑出来,同步到subtree工程,如果提交有很多,速度会非常慢。

方法二 拆分代码再push[推荐]

bash 复制代码
git subtree split --rejoin -P src/common
git subtree push -P src/common common master

如果想要split成功,一定要去除 commit msg 的校验。

方法三 拆分代码到单独分支

bash 复制代码
git subtree split --rejoin -P src/common -b split-common
git push common split-common

首先将 common 拆分到父仓库的 split-common 分支,可以通过 checkout 到这个分支查看内容。

2.5 删除子仓库

bash 复制代码
git rm -r src/common

2.5 细节

在开发一个需求的时候, A端更改了 common 后,其他人只需要向以前一样在父仓库拉取代码。而当想在B端使用 common 代码,则需要将A端的代码同步到common 仓库,B拉取一下就行。

问题

git subtree split 无效

我们项目是基于 umi 脚手架开发的项目,这个脚手架自带了一个 gitHooks 会对 commit 的msg进行校验,而git subtree split 的原理就是通过 msg 进行判断。 解决方法:去掉 package.json 中的 commit 校验

json 复制代码
{
  "gitHooks": {
  }
}

修改后没有同步

问题描述

修改一个后,没有push代码,慢慢导致后面两端的子仓库出现差异, 出现代码冲突。

解决方法

每次修改公共的代码都要 push 和 pull, 手动保持一致。

git subtree pull 冲突

错误信息如下

vbnet 复制代码
fatal: refusing to merge unrelated histories

解决方法, 在 git subtree pull 时添加 --squash 参数, 类似于 git push 的 --allow-unrelated-historie参数。

git subtree push 不上去

bash 复制代码
git push using:  common feature/20221214
cache for f1156335aca1314ff75ba328a850cbdd13affb5a already exists!

stackoverflow.com/questions/6...

暂时无法解决

参考文章

# 为什么你的公司不应该使用git submodule # Git subtree用法与常见问题分析 # 用 Git Subtree 在多个 Git 项目间双向同步子项目 # Git subtree 要不要使用 --squash 参数 # 掌握Git的subtree[译]

相关推荐
LCY13310 小时前
spring 中的DAO是什么
运维·git·jenkins
柚几哥哥13 小时前
IntelliJ IDEA全栈Git指南:从零构建到高效协作开发
java·git·intellij-idea
遇到困难睡大觉哈哈13 小时前
Git推送错误解决方案:`rejected -> master (fetch first)`
大数据·git·elasticsearch
ON.LIN13 小时前
Git提交本地项目到Github
git·github
九月镇灵将14 小时前
6.git项目实现变更拉取与上传
git·python·scrapy·scrapyd·gitpython·gerapy
wuyijysx14 小时前
ubuntu git cola gui
git·软件工具
九月镇灵将15 小时前
GitPython库快速应用入门
git·python·gitpython
程序猿chen16 小时前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算
Code_Geo1 天前
Git操作指南
git