最佳实践:Node.js集成Git方案梳理

1. 背景

在开发一款js静态分析工具时,我遇到了一些git相关的需求:

  • 通过git比较出工程中两个分支的改动文件
  • 跨分支读取

针对这个两个问题,我们先看看用 git 命令如何操作:

1.1 分支比较

通过如下的 git 命令即可进行分支比较:

css 复制代码
git diff [分支1] [分支2] --name-status

打印结果可能如下:

css 复制代码
M       a.js
D       b.vue
A       c.vue
R092    .whistle.js     .whistle111.js
...

这里每一行就是一个改动文件,空格前是改动类型,空格后是改动的具体文件。

M: 修改 D: 删除 A: 新增 R: 重命名,这里的 092 代表是改动前后两个文件的相似度。[了解更多]

1.2 跨分支读取

这里先说一下跨分支读取的意思:假如我现在处于a分支中开发,我想要实现在不切换分支的情况下读取b分支某个文件的内容和某个文件夹下面的文件列表。

通过调研,发现可以通过 git cat-file 和 git ls-tree 来实现:

  • 读取文件内容
bash 复制代码
#读取文件
git cat-file -p [分支]:[文件相对路径]
  • 列出目录下的文件及文件夹列表
bash 复制代码
git ls-tree [分支]:[目录相对路径]

所以,现在的问题是如何在nodejs中集成这功能,且支持打包到 Cli工具和 Vscode 拓展。

2. 实现方案

2.1 exec 调用 Git 命令

首先想到最简单的方案就是通过Node.js 的 child_process 模块中的 exec调用Git命令:

typescript 复制代码
import { execSync } from "child_process";

function getChangeFileList(baseBranch: string, targetBranch: string) {
  return execSync(`git diff ${baseBranch} ${targetBranch} --name-status`, {
    cwd: projectDir,
  }).toString().trim();
}

这种方法使用简单,无需依赖外部的包,且能够被打包到node cli工具和vscode插件中。

目前有许多js库都基于这个原理,例如 simple-git,可以进一步简化使用的成本。

但经过一段时间的使用,发现这种方式存在两个问题:

  1. 依赖本机安装的Git,且需要正确配置环境变量(一般开发都会安装git,不是很严重的问题)。
  2. 通过创建子进程调用外部命令,而创建子进程是有性能开销的,当调用太多次后有性能问题,具体有多差可以看后面的对比。

由于有了这些问题,所以调研实践了市面的其他几种方案。

2.2 execFile 调用 Git 可执行文件

上面我们介绍了通过 child_process模块中的 exec(execSync是exec的同步形式)方法,它是通过调用shell来执行命令的,而在这个模块中还有一个execFile 方法,可以通过git程序的路径来执行:

ini 复制代码
const res = execFileSync("/usr/bin/git", ["cat-file", "-p", `master:packages.json`]);

下面是nodejs文档的描述

child_process.exec() 和 child_process.execFile() 之间区别的重要性可能因平台而异。 在 Unix 类型的操作系统(Unix、Linux、macOS)上,child_process.execFile() 可以更高效,因为它默认不衍生 shell。 但是,在 Windows 上,.bat 和 .cmd 文件在没有终端的情况下无法自行执行,因此无法使用 child_process.execFile() 启动。

可以看到这种方法性能有所提升,但是必须指定git的位置。

2.3 dugite

github.com/desktop/dug...

github.com/desktop/dug...

dugite 是一个execFile原理实现git绑定的js库,但于上面不同的是,它在安装后会调用postinstall钩子去下载一个精简版版的git,所以不需要手动指定git路径。

postinstall 钩子

node_modules
中的可执行文件

再从dugite的github可以看成,dugite是github-desktop的一部分,而github-desktop是基于electron开发的,那么可以推测出这个库对于开发跨端的桌面程序有很好的支持。

2.3 NodeGit

官网:www.nodegit.org/

NodeGit 是一个基于 C++ 实现的Node.js 原生模块,实现了对 libgit2 的封装。

ini 复制代码
const repo = await NodeGit.Repository.open(gitBasePath);

经过使用发现这个库优点如下:

  1. 功能强大,API复杂
  2. 原生模块性能好
  3. API基于Promise来实现。

但是使用了这个库也发现了一些问题:

  1. 原生模块导致安装复杂,比如在我的mac m1 电脑安装会失败,需要指定安装^0.28.0-alpha.21 这个版本。
  2. 在一些低版本Linux 上面安装会失败,需要手动升级GCC版本。
  3. vscode插件不支持原生模块。

2.4 isomorphic-git

isomorphic-git.org/

isomorphic-git 是一个纯 JavaScript 的库,提供了跨浏览器和 Node.js 环境使用的 Git 功能。它不依赖于外部的 Git 客户端或二进制文件,而是通过 JavaScript 实现了 Git 的核心功能。

使用 isomorphic-git 实现跨分支读取:

javascript 复制代码
import * as git from "isomorphic-git";
import fs from 'fs';

const oid = await git1.resolveRef({
    fs: fs,
    dir: projectDir,
    ref: 'master',
});

let cache = {};
const res = await git1.readBlob({
    fs: fs,
    dir: projectDir,
    oid,
    cache,
    filepath: 'packages.json'
 });
 console.log(res.blob);

这个库支持通过 cache 参数缓存结果,提高批量读取文件的速度。

3. 总结

下面我会从性能、浏览器支持、vscode插件机制几个角度进行对比:

exec + git execFile + git dugite NodeGit isomorphic-git
读取 620个不同文件 11888 ms 9357 ms 4002 ms 92ms 开启cache: 810 ms 不开cache: 12828 ms
star - - 443 5.5k 7.1k
浏览器支持 不支持 不支持 不支持 不支持 支持
vscode插件 支持 支持 不支持,需要 npm install下载依赖 不支持 支持
node cli 工具 支持 支持 支持 支持,但可能需要升级系统的库 支持
API支持 需要手写git命令 需要手写git命令 需要手写git命令 API封装度高,使用复杂 API封装度高,使用较为简单

根据上述表格,可以得到如下结论:

  1. isomorphic-git综合能力最强,可以兼容大部分场景。
  2. 需要浏览器支持使用isomorphic-git
  3. 需要性能使用 nodegit
  4. electron 集成可以考虑使用 dugite,github 官方背书
  5. 不依赖外部git的方案:dugite、nodegit、isomorphic-git

但接入哪一个,还需要在项目中对比。

相关推荐
MyhEhud36 分钟前
Kotlin 中 also 方法的用法和使用场景
前端·kotlin
小莫爱编程1 小时前
HTML,CSS,JavaScript
前端·css·html
陈大鱼头1 小时前
AI驱动的前端革命:10项颠覆性技术如何在LibreChat中融为一体
前端·ai 编程
Gazer_S2 小时前
【解析 ECharts 图表样式继承与自定义】
前端·信息可视化·echarts
剪刀石头布啊2 小时前
视觉格式化模型
前端·css
一 乐2 小时前
招聘信息|基于SprinBoot+vue的招聘信息管理系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·招聘系统
念九_ysl2 小时前
Vue3 + ECharts 数据可视化实战指南
前端·信息可视化·echarts
Gazer_S2 小时前
【Auto-Scroll-List 组件设计与实现分析】
前端·javascript·数据结构·vue.js
前端加油站2 小时前
前端开发人员必备的Mac应用
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(四)——虚拟DOM批处理、文档碎片池、重排规避
前端·性能优化·dom