likes
comments
collection
share

浅析Git Subtree子仓库在实际项目中的应用

作者站长头像
站长
· 阅读数 75

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第7篇文章,点击查看活动详情

为什么需要使用Git Subtree

先说结论:关于子仓库或者说是仓库共用,git 官方推荐的工具是 git subtree。

在我们实际的项目开发过程中,公共的代码或者模块是必定会出现的,为了不重复写相同的代码;普遍的做法就是将其抽取成一个公共模块,这个模块由不同的使用者引用。

作为 Java 工程师,可能会选择将这一部分打包封装成一个jar,并且将其推送到 Maven 的私有仓库,各个使用者将其添加到 pom 文件引用即可。作为前端工程师,可能会选择将这一部分打包封装成一个自定义的 plugin,将其推送至 npm 的私有仓库,团队内各个使用者去安装引用即可。

但是,有没有更好的方式呢?因为使用这种方式,对使用者来说,并不是透明的,假如我们需要修改一个业务,这个业务设计到业务代码和这块公共代码的同步修改,那么使用者是不方便去改这块代码的。

接下来,就一起探讨一种更好的管理方式:git subtree。

共用代码的需求及处理方式

1、需求背景:项目A与项目B存在公用模块,在项目A中修改Bug或增加新功能需要同步到项目B中

2、需求分析:A项目中依赖了子项目B,最方便的方式自然是直接在A项目里改B子项目对应的目录里的代码,然后测试通过后,直接提交代码,这个更改也提交到B子项目的 Git仓库里。同时子项目B也可以单独提交到 Git 仓库,再在A项目里把子项目B的代码update。

3、现有方案

(1)Git Submodule:这是Git官方以前的推荐方案

(2)Git Subtree:从 Git1.5.2 开始,Git 新增并推荐使用这个功能来管理子项目

(3)npm 等包管理工具

npm(前端)、maven(后端) 等更侧重于包的依赖管理,虽然能够做到在不同项目中同步同一块代码的,但没法双向同步,修改维护公用代码包也比较麻烦,更适用于子项目代码比较稳定的情形。

Git Submodule 和 Git Subtree 都是官方支持的功能,不具有依赖管理的功能,但能满足我们的要求。Git Subtree相对来说会更好一些,git 官方建议使用 git subtree。

4、Git Subtree 好在哪里?

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

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

它是怎么做到的呢?后面会通过实操记录简单说下原理。

什么时候需要 Subtree?

1、当多个项目共用同一模块代码,而且这块代码跟着项目在快速更新的时候。

2、把一部分代码迁移出去独立为一个新的 git 仓库,但又希望能够保留这部分代码的历史提交记录。

Git Subtree的原理与实际应用

首先,你需要2个主项目,我利用之前的demo项目、demo2项目,还要有一个被多个项目共用的subtree项目。我们通过简要讲解使用Subtree来同步代码的过程来解释Subtree的原理

1、初始化子项目subtree

通过我之前的demo项目做下示例

cd demo项目的路径  
git subtree add --prefix=用来放subtree项目的相对路径 subtree项目git地址 xxx分支
PS D:\demo\vue-button-test> git subtree add --prefix=/subtree https://gitee.com/***/npm_test.git master
git fetch https://gitee.com/goloving/npm_test.git master
From https://gitee.com/goloving/npm_test
 * branch            master     -> FETCH_HEAD
error: Invalid path 'C:/Program Files/Git/subtree/README.md'
error: Invalid path 'C:/Program Files/Git/subtree/index.js'
error: Invalid path 'C:/Program Files/Git/subtree/package.json'
error: Invalid path 'C:/Program Files/Git/subtree/plugins/lib/button.vue'
fatal: C:/Program Files/Git/subtree: 'C:/Program Files/Git/subtree' is outside repository
PS D:\demo\vue-button-test> git subtree add --prefix=subtree https://gitee.com/goloving/npm_test.git master
prefix 'subtree' already exists.
PS D:\demo\vue-button-test> git subtree add --prefix=subtree https://gitee.com/goloving/npm_test.git master
git fetch https://gitee.com/goloving/npm_test.git master
From https://gitee.com/goloving/npm_test
 * branch            master     -> FETCH_HEAD
Added dir 'subtree'
PS D:\demo\vue-button-test>

遇到3个报错:

(1)Working tree has modifications. Cannot add. 实际上工作树没有更改,解决:关闭终端,重新开启终端即可

(2)--prefix=/subtree 应该是相对路径,不是绝对路径,所以写 /subtree 匹配到 C:/Program Files/Git/ 去了

(3)--prefix=subtree 刚开始以为必须新建这个目录,发现不是的,新建会报错,删除即可

这样的命令,把subtree即npm_test项目的代码下载到--prefix所指定的subtree目录中,并在demo项目里自动产生一个commit(就是把npm_test目录的内容提交到demo项目里)

浅析Git Subtree子仓库在实际项目中的应用

我们再用一个demo2项目做同样的操作

2、像往常一样更新代码

大家在demo项目里各种提交commit,其中有些commit会涉及到subtree目录的更改,正如前面提到的,这是没任何关系的,大家也不会感受到有任何不一样。

比如我们在 npm-test 项目里button按钮后随便加个文字:subtree,看下图 demo 项目生效了

浅析Git Subtree子仓库在实际项目中的应用

然后我们把更改的所有内容 git 提交到 demo 项目仓库,我们可以看到下面全部的 commit 记录

浅析Git Subtree子仓库在实际项目中的应用 浅析Git Subtree子仓库在实际项目中的应用

3、提交更改到子项目的Git服务器

关键的地方来了:当维护这个demo项目 subtree 的人希望把最近这段时间对demo项目subtree目录的更改提交到subtree对应的npm_test项目的 Git 服务器上时,他执行一段类似于这样的命令:

cd demo项目的路径  
git subtree push --prefix=用来放subtree项目的相对路径 subtree项目git地址 xxx分支
PS D:\demo\vue-button-test> git subtree push --prefix=subtree https://gitee.com/***/npm_test.git master
git push using:  https://gitee.com/goloving/npm_test.git master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 384 bytes | 384.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0)
remote: Powered by GITEE.COM [GNK-6.3]
To https://gitee.com/goloving/npm_test.git
   adbf133..bbe8c7b  bbe8c7b22181acc371c7118f6392fafa9448ce4f -> master
PS D:\demo\vue-button-test>

Git 会遍历所有的commit,从中找出针对subtree目录的更改,然后把这些更改记录提交到subtree对应的npm_test项目的Git服务器上。

然后我们就可以看到 npm_test 项目上多个对button更改的记录

浅析Git Subtree子仓库在实际项目中的应用

4、更新子项目新的代码到父项目

现在subtree npm_test项目有新代码了,demo2项目也想使用这些新代码,维护demo2项目这个Subtree的人只要执行

cd demo2项目路径
git subtree pull --prefix=subtree项目的路径 subtree项目git地址 xxx分支
PS D:\其他\big-data-view1>  git subtree pull --prefix=subtree https://gitee.com/goloving/npm_test.git master
Working tree has modifications.  Cannot add.
PS D:\其他\big-data-view1>  git subtree pull --prefix=subtree https://gitee.com/goloving/npm_test.git master
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 2), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), done.
From https://gitee.com/goloving/npm_test
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 subtree/plugins/lib/button.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
PS D:\其他\big-data-view1>

当有未提交记录时会报这个错误:Working tree has modifications. Cannot add. 解决:将未提交记录全部提交即可

接下来我们就可以看到 demo2 项目里的 button 按钮就更新为最新的了

浅析Git Subtree子仓库在实际项目中的应用

这样就可以将demo2项目里subtree目录里的内容更新为npm_test项目xxx分支的最新代码了。

转载自:https://juejin.cn/post/7143927598450475044
评论
请登录