Sparse Checkout 在 Monorepo 工程下的应用
Posted Songlcy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sparse Checkout 在 Monorepo 工程下的应用相关的知识,希望对你有一定的参考价值。
我们现在有越来越多的项目都是前后端分离的架构,所以在一个 Git Repo 里面同时放前后端代码是很常见的情况。不过,问题来了,如果前后端分离的很干净,若是前端人员不想要看到“后端”的原始代码,那 Git 有办法做到“部分取出”的功能吗?是的,还真的有!这篇文章我就来说说这个好用的功能。
Sparse checkouts
Sparse checkouts 是一个从 Git 2.25 才开始支持的功能,主要用途就是帮助你取得一个 Repo 的部分内容,大幅减少本机硬盘空间的占用,也可以帮助你更加专注在当前的开发项目。这样的机制尤其对目前 Monorepo 正夯的时候,提供一个绝佳的解决方案。
英文的 Sparse 是一个形容词,表示“稀疏的”、“零落的”的意思,代表你仅会从 Repo 取出“零星的”档案!我们从 Git 官网的 git-sparse-checkout 文件可以看到他的定义:
Reduce your working tree to a subset of tracked files
基本使用方式
而 Sparse checkouts 的使用方式,其实也就是两个步骤而已:
1、先通过 git clone 取得一个 Repo 并启用 Sparse checkouts 功能
这个动作是在复制远程储存库内容时,直接启用 Sparse checkouts 功能并套用默认样式清单,默认只会取出根目录下的文件:
git clone --filter=blob:none --sparse https://github.com/doggy8088/MonorepoAspNetCoreWithAngular.git
cd MonorepoAspNetCoreWithAngular
注意: 这个命令依然会下载完整的 Git Repo 内容,只是默认不会取出所有文件到工作目录而已!
2、启用圆锥模式 (Cone mode)
目前 Git 的 Sparse checkouts 支持两种模式,默认为 非圆锥模式 (non-cone mode),但建议改用 圆锥模式 (cone mode) 效能比较好!
git sparse-checkout init --cone
3、接着你可以通过 git sparse-checkout 明确指定你想要取得的文件夹名称
这个命令会指定取得指定文件夹下的所有文件,但在圆锥模式下,默认会包含根目录下的所有文件喔!
git sparse-checkout set "MonorepoAspNetCoreWithAngular/ClientApp"
TIPS: 快速下载超大 Repo 的小技巧
你可以在 git clone 的时候套用 --depth 1 命令,仅取得最近 1 个版本的相关 Blob 物件,这样就可以大幅缩短 git clone 的时间。我以 ASP.NET Core 原始码项目为例,正常的 git clone 在高速网路下也要十几秒才能下载完毕,但通过以下命令就只要 2 秒就可以复制完毕:
git clone --depth 1 --filter=blob:none --sparse https://github.com/dotnet/aspnetcore.git
cd aspnetcore
注意: 使用 --sparse 默认就只会取出 (Checkout) 根目录下的所有文件而已,但沒有任何「子文件夹」喔。
然而,你若只想取回 /docs 文件夹的話,就只要用以下命令即可立即下载这个文件夹下的用到的 Blob 物件,速度極快:
git sparse-checkout set "/docs"
圆锥模式 cone mode
Git 的 Sparse checkouts 支持两种模式, 非圆锥模式 (non-cone mode) 与 圆锥模式 (cone mode),主要差別在于解析 路径样式清单 (Pattern Set) 的格式不同!
事实上,你使用 git sparse-checkout 所做的任何操作,都会记录在一个 .git/info/sparse-checkout
设置文件中,這是一个文本文件 (Text file),內容跟 .gitignore 的格式有点相似,但你要特別注意在不同的模式下,其內容所代表的意义是不同的!
非圆锥模式 (non-cone mode)
先说,虽然这是 Git 的默认值,不过不建议使用,主要是效能考量!🔥
在 非圆锥模式 下,这个 .git/info/sparse-checkou
t 设置文件的内容会采用 FULL PATTERN SET 语法,其内容格式与 .gitignore 完全一样。
那什么是 FULL PATTERN SET 呢?简单来说,就是这些 Patterns 是对整个 Repo 的文件路径进行比对,所以你可以用“正向比对”,也可以用 ! 进行“反向比对”,设置上比较灵活。不过,这层灵活性的唯一的缺点就是效能较差,因为当 Git 在做 Checkout 动作时,每一个文件在取出时,每一条规则都要判断,所以复杂度是 O(M*N) 这么多,这意味着文件越多或规则集越多,取出(Checkout)的速度就越慢!
我举个简单的例子,以下列命令为例,该项目默认使用了非圆锥模式,然后指定了 MonorepoAspNetCoreWithAngular/ClientApp 路径。事实上,这个 MonorepoAspNetCoreWithAngular/ClientApp 所代表的意义,是指“所有目录与子目录下有包含 MonorepoAspNetCoreWithAngular/ClientApp 的路径,都在取出的范围内”。
git sparse-checkout set "MonorepoAspNetCoreWithAngular/ClientApp"
你如果设定 /MonorepoAspNetCoreWithAngular/ClientApp
路径,就代表著只有“位于根目录下的 /MonorepoAspNetCoreWithAngular/ClientApp
路径,才包含在取出范围内”。
git sparse-checkout set "/MonorepoAspNetCoreWithAngular/ClientApp"
圆锥模式 (cone mode)
在 圆锥模式 下,这个 .git/info/sparse-checkout
设置文件的内容会采用 CONE PATTERN SET 语法,这个语法只能说近似于 .gitignore 的格式,但比对上稍微再严格一些,而且有些特殊的规则。
基本上圆锥模式下的 CONE PATTERN SET 规则集有两大特性:
-
Recursive: 你所指定的路径,默认包含所有的子目录下的所有文件路径。
-
Parent: 你所指定的路径所在的目录下的所有文件也都包含在内!(有点绕口,需要思考一下)
我举个简单的例子,以下列命令为例,我将该项目启用了圆锥模式,然后指定了 MonorepoAspNetCoreWithAngular/ClientApp
路径:
git clone --filter=blob:none --sparse https://github.com/doggy8088/MonorepoAspNetCoreWithAngular.git
cd MonorepoAspNetCoreWithAngular
git sparse-checkout init --cone
git sparse-checkout set "MonorepoAspNetCoreWithAngular/ClientApp"
这个 Pattern 将会包含:
Recursive: 包含所有子目录所有路径 (MonorepoAspNetCoreWithAngular/ClientApp/**)
与
Parent: 包含上层的 /MonorepoAspNetCoreWithAngular/*/*
目录下的所有文件
所以我们可以说,以下圆锥模式的样式集(CONE PATTERN SET):
MonorepoAspNetCoreWithAngular/ClientApp
会等同于以下非圆锥模式的样式集(FULL PATTERN SET):
/* 根目录所有档案
!/*/ 排除根目录下的所子目录 (没有排除档案)
/MonorepoAspNetCoreWithAngular/ 包含这个子目录以及底下所有路径(目录+档案)
!/MonorepoAspNetCoreWithAngular/*/ 排除这个子目录下的所有子目录 (没有排除档案)
/MonorepoAspNetCoreWithAngular/ClientApp/ 包含这个子目录以及底下所有路径(目录+档案)
在圆锥模式下,你无法排除已经包含在这些 Pattern Set 在内的所有文件。
如果你真的想要精准的包含与排除文件,只能使用非圆锥模式 (non-cone mode)!
为什么要取名叫圆锥模式?
我从 Bring your monorepo down to size with sparse-checkout 文章中撷取两张图片来说明。
假设你的 Monorepo 有以下目录结构:
若你只想取出 /client/android
目录下的源码,那么你若用圆锥模式的话,就只要用一条规则就可以取出你要的档案:
git sparse-checkout set "client/android"
你从这个文件取出的模式来看,整个文件夹结构就好像一个“圆锥体”,而取得文件的方式是从上到下以“圆锥状”的方式取出,圆锥的顶端就是项目的“根目录”,而之后每一层的档案也都需要取出,一直取到某一层之后,就会取出以下的所有档案。
我只能说取名是一种艺术,大家要多发挥想像力!😄
常用 Sparse checkouts 命令与参数
1、启用 Sparse checkouts 功能
# 启用非圆锥模式 (non-cone mode)
git sparse-checkout init
# 启用圆锥模式 (cone mode)
git sparse-checkout init --cone
2、取得 Sparse checkouts 的路径样式清单
git sparse-checkout list
注意: 如果你的 Repo 并没有启用过 Sparse checkouts,第一次使用会出现 fatal: this worktree is not sparse 错误信息。
3、设定 Sparse checkouts 的路径样式清单 (.git/info/sparse-checkout)
使用 git sparse-checkout set 命令会直接覆盖现有的路径清单:
git sparse-checkout set "/MonorepoAspNetCoreWithAngular/ClientApp"
git sparse-checkout list
执行完 git sparse-checkout set 命令之后,你的工作目录下所有文件就会立即反应出结果,执行前请先确认拥有一个干净的工作目录!
你可以使用以下命令调整 Sparse checkouts 回覆到默认值:
git sparse-checkout set ""
git sparse-checkout list
无论你使用哪种 Sparse 模式,执行完之后预设都只会剩根目录下的档案!
4、一次设定多组 Sparse checkouts 的路径样式清单
设定多组 Sparse checkouts 路径样式时,套用顺序很重要!
git sparse-checkout set "!/*" "/MonorepoAspNetCoreWithAngular/ClientApp" ".git*"
git sparse-checkout list
此范例仅适用于非圆锥模式!(FULL PATTERN SET)
5、加入新路径到 Sparse checkouts 的路径样式清单
git sparse-checkout set "!/*" "/MonorepoAspNetCoreWithAngular/ClientApp"
git sparse-checkout add ".git*"
git sparse-checkout list
此范例仅适用于非圆锥模式!(FULL PATTERN SET)
6、重新套用 Sparse checkouts 的路径样式清单
这个命令仅用于你手动调整 .git/info/sparse-checkout 设定档内容之后执行。
git sparse-checkout reapply
7、停用 Sparse checkouts 功能
这个命令会将所有工作目录中的档案完整取出:
git sparse-checkout disable
注意: 此命令不会更动 .git/info/sparse-checkout 设定档中的路径样式清单。
8、将 Sparse checkouts 功能切换至圆锥模式 (cone mode)
git sparse-checkout disable
git sparse-checkout init --cone
#git sparse-checkout set
git sparse-checkout list
由于圆锥模式与非圆锥模式的 Patterns 并不相容,切换过程记得要重新检视过!
将 Sparse checkouts 功能切换至非圆锥模式 (non-cone mode)
git sparse-checkout disable
git sparse-checkout init
#git sparse-checkout set
git sparse-checkout list
由于圆锥模式与非圆锥模式的 Patterns 并不相容,切换过程记得要重新检视过!
以上是关于Sparse Checkout 在 Monorepo 工程下的应用的主要内容,如果未能解决你的问题,请参考以下文章
Sparse Checkout 在 Monorepo 工程下的应用
Sparse Checkout 在 Monorepo 工程下的应用
如何在 nrwl monorep 中调试 NestJS 应用程序