我花五分钟写了个简易的git

3,750 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

前言

大家好,我是小阵 🔥,一路奔波不停的码字业务员
身为一个前端小菜鸟,总是有一个飞高飞远的梦想,因此,每点小成长,我都想要让它变得更有意义,为了自己,也为了更多值得的人
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~😋
加我微信:zzz886885,邀你进群,一起学习交流,摸鱼学习两不误🌟

开开心心学技术大法~~

开心

来了来了,他真的来了~

正文

看起来有点高大上,其实就是通过cli自己做了个git命令的二次封装而已。

当然,这个功能也可以通过git alias来实现

看到这里小伙伴其实已经可以猜到下面要做的事情了,简单来说就是

testcli acm xxxx通过node转成git add . && git commit -m xxx而已,当然这只是一个示例,更多功能还有待拓展。

重要的是实现过程和思路,之前掘金也有很多类似的教程,我借花献佛而已,希望大家不要介意!

直接掘金搜索cli即可

初始化cli

mkdir testcli && cd testcli
npm init -y

新建一个testcli目录,并且进入到testcli目录执行npm init -y来创建一个初始化的npm仓库

然后通过package.jsonbin字段创建一个cli入口

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "bin": {
    "testcli": "bin/index.js"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chalk": "^5.0.1",
    "child_process": "^1.0.2",
    "commander": "^9.3.0",
    "inquirer": "^8.2.4"
  }
}

关键是上面的bin字段,指向了bin/index.js

主要的cli功能都是在这个bin/index.js中实现的。

#! /usr/bin/env node
// 文件的第一行一定要是这样,告诉终端要基于电脑的env环境,通过node来执行该文件
...

link全局命令

可以看到上面我们定义了bin的key是testcli,value就是bin/index.js,那么按照我们的预期,是希望在终端输入testcli来执行我们定义的bin/index.js文件。

实际上我们在运行时会发现终端提示了command not found: testcli

为什么会这样呢?原来是我们平时所输入的类似于npmcnpm命令等都是在全局环境变量中注册过的,所以我们可以直接在终端中通过输入已经注册好的变量来唤起指定的cmd入口,这个里的cmd入口其实就是类似我们上面自己定义的bin/index.js文件。

那我们要怎样注册这个全局变量呢?

1.通过npm -g testzzz 来注册

当然目前来看,这是不可能的,因为我们的testzzz还在本地,并没有发布到npm上。

2.通过npm link testcli 来做临时的全局环境绑定

等项目上线之后再通过npm -g testzzz来安装即可。

git命令包装

#! /usr/bin/env node

import { Command } from 'commander'
import child_process from 'child_process'
import util from 'util'
import chalk from 'chalk'
import { readFile } from 'fs/promises'

const packageJson = JSON.parse(
	await readFile(new URL('../package.json', import.meta.url))
)

const program = new Command()

const exec = util.promisify(child_process.exec)

program
	.command('acm')
	.description('执行回退到上一个版本')
	.option("-m --message", "commit message")
	.action((name) => {
		console.log('name', name)
		try {
			exec(`git add . && git commit -m`).then(({ stdout }) => {
				console.log(chalk.green(stdout))
			})
		} catch (err) {
			console.log(chalk.red(`err: ${err}`))
		}
	}).parse(process.argv)

可以看到上面,我们用到了commanderchild_execchalk,utilfs/promises这几个包

其中

  • commander 是用来获取用户在终端的输入的
  • child_exec 是启用子node容器帮助执行node指令的
  • chalk 是用来润色我们的输出的
    • 本质上是借用了console.log('xxxs%','color:red')类似这种的可以书写css的log来实现的
  • util 是将普通异步封装成promise风格的工具包
    • 这个包不想用的小伙伴可以不用,上面直接通过child_exec.exec(cmd,(err,res)=>{...})也可
  • fs/promises 是fs的promise风格的fs包
    • 这个也可以直接引入fs,然后使用时用node的callback风格来调用即可

可以看到我们上面通过commendercommand('acm')来监听数输入的testcli acm这样的指令。

然后通过action()来触发我们自定义的动作,在action中我们通过exec('git add . && git commit -m')来执行node指令。

并且将返回的结果stdout通过console.log(chalk.green(stdout))来打印出来。

git alias

兄弟们可以自己尝试下类似的功能,当然如果是通过git.alias来实现的话也很简单,只需要在终端输入以下即可

git config -g alias.acm = '!git add . && git commit -m' 

如果提示命令过长或者alias.acm绑定不正确的话,可以手动打开git config的全局配置文件.gitconfig,然后在文件的alias下面添上!git add .&& git commit -m即可。

image.png

如何找到gitconfig位置?

git config  -l --show-origin

image.png

结语

往期好文推荐「我不推荐下,大家可能就错过了史上最牛逼vscode插件集合啦!!!(嘎嘎~)😄」