自定义 Git Hook

前言

前端同学大概都熟悉 husky 这个工具,他可以直接在项目中添加 git hooks,主要解决了 git hooks 不会同步到 git 仓库的问题,保证了每个开发人员的本地仓库都能执行相同的 git hooks。

但是 husky 毕竟是一个 JS 生态的工具,依赖于 npm 安装和 npm 的 script hook 才能达到最佳效果,放到后端项目中,初始化一堆 npm 配置文件,还需要开发人员手动安装,多多少少会显得不太合适。

恰巧我们项目一直被一个提交问题所困扰,所以我前段时间给项目写过一个命令行工具,用于初始化 git hook, 将编写 Git Hook 这个过程整理一下。

Git Hook

本文不对 git hook 类型做过多介绍,主要是针对编写 commit-msg hook 作为演示展开,commit-msg 接收一个存有当前提交信息的临时文件的路径的参数,我们可以读取这个文件获取用户提交信息, 如果该 hook 脚本以非零值退出时 Git 将放弃提交,因此,我们可以用来在提交通过前验证项目状态和提交信息。

Git Hook 示例

通常情况下,在当前项目的 <project root>/.git 目录下会有一个 hooks 目录,里面会有官方提供的各个 hook 的示例,如果没有的话也不用担心,新建一个 hooks 目录即可。

Pasted image 20231111000833.png

示例代码会有一个 .sample 后缀,去掉后缀后,hook 文件就生效了,提供的示例大部分都是 shell 编写的,我们在这里看一下示例中的 commit-msg

Pasted image 20231111001244.png

这个示例脚本的功能是检查文件中是否存在重复的 Signed-off-by 行,下面对出现的命令做逐一解释:

  1. grep '^Signed-off-by: ' "$1": 使用 grep 命令在文件中查找以Signed-off-by: 开头的行。
  2. sort: 使用 sort 命令对查找结果进行排序。
  3. uniq -c: 使用 uniq 命令计算排序后的行的数量,并将结果按数量进行排序。
  4. sed -e '/^[ ]*1[ ]/d': 使用 sed 命令删除数量为 1 的行,即只保留数量大于 1 的行。
  5. "$(...)": 将命令的执行结果赋值给变量 test。
  6. || { echo >&2Duplicate Signed-off-by lines.; exit 1; }: 如果 test 变量为空(表示没有重复的 Signed-off-by 行),则执行后面的代码块;否则,输出错误信息并退出脚本。

编写 Git Hook

提供的示例脚本比较复杂,理解起来多少有些困难,我们先使用 shell 脚本编写一个简单的示例。
这个脚本的功能是检查 commit-msg 中是否在开头添加 issue id。

#!/usr/bin/env shissueId=$(cat $1 | sed -n 's/^\(#[0-9]*\) .*/\1/p')if [ ! $issueId ]
thenecho "commit msg 必须开头添加 issue id"exit 1
fi

在上面这块代码中,参数 $1 是存有当前提交信息的临时文件的路径,我们通过 cat $1 读取到文件中的提交信息,然后通过 sed 去正则匹配信息中是否存在 issue id, 当没有 issueId 时,通过 exit 1 退出脚本。

  • 下图是一个校验未通过的拦截示例

  • 下图是一个成功提交的示例。

我们用了几行代码就实现了一个小功能,所以说编写 git hook 并不是一件复杂的事,但是对于大多数开发者而言,对于 shell 可能仅仅停留在了编写简单命令的阶段,开发起来肯定不如自己擅长的语言随心所欲,再加上一些命令可能还受限于宿主机的环境问题等等,所以我们接下来直接使用自己擅长的语言编写 git hook。

使用 NodeJS 编写 GitHook

git hook 允许你使用任何你熟悉的脚本语言,比如 perl、python、node 等等, 我们只需要在文件头部加入声明即可。

#!/usr/bin/env node

如上所示,这是一个 node 脚本的文件头,我们现在重新将使用 shell 编写的 检查 commit-msg 中是否在开头添加 issue id 的功能,使用 node 脚本实现一遍。

#! /usr/bin/env node
const fs = require('fs')const [_, __, msgFilePath] = process.argv
const msg = fs.readFileSync(msgFilePath, { encoding: 'utf8' })
const checkIssueId = /^#\d+\s+.*/.test(msg)if(!checkIssueId) {console.log("commit msg 必须在开头添加 issue id")process.exit(1)
}

我们通过 process.argv 获取到调用脚本时传入的参数,在通过 nodeJS 的 fs.readFileSync 方法读取到文件中的提交信息,这时就可以按照自己的需求去完善功能了,当不符合规则时,我们通过调用 process.exit(1) 结束调用进程,注意参数 1 可以是除 0 以外的任何数值,因为 git 会判断是否以非零值结束。

还能做些什么?

文中提供的示例仅仅是简单校验了一下提交信息,但实际上还可以做更多的事情,比如说直接在脚本中调用 github、gitee、gitlab…平台的 API 获取项目的 issue ID 列表,从而达到校验 issue id 是否存在的问题,再或者我们可以在 hook 中统一在提交信息尾部添加 某些信息(用户、提交文件数) 等等。

编译型语言示例

脚本语言可以直接在文件头声明即可,编译型语言是没办法这么做的,这里提供一个通用的处理方法,适用于任何语言。

基本所有语言都是支持命令调用的,比如 node xxx.js, python xxx.py, java xxxxx.class, 既然这样,我们可以直接在 shell 中调用相应的命令即可。

shell

下面以调用 java 作为示例, 我们先调用 javac 将源代码编译为 class 文件,在通过 $() 获取 java 调用的结果,因为通过 shell 获取文件内容更方便,所以我们可以直接在 shell 中调用 cat 命令获取提交信息,最终,我们只要根据调用的代码有没有返回异常信息作为判断依据即可。

#! /usr/bin/env shmsg="$(cat $1)"cd $(pwd)/.git/hooks
javac HookExample.java
checkMsg="$(java HookExample "$msg")"
err="$(echo $checkMsg | grep "fail: ")"if [ "$err" != "" ]
thenecho $errexit 1
fi

这里为了简单,我直接在脚本中临时编译 java 文件为 .class 文件,再调用 .class,这样其实很不合适,实际运用时,我们可以直接调用打包后的 jar 包,可以免去很多麻烦。

java

下面这段代码,我们写了一个 main 方法,直接拿到了提交信息进行检测,当不符合标准时控制台输出错误信息,我们可以统一一个错误信息的标识开头,比如当前示例的 fail: ,这样我们在 shell 中检查日志输出时可以过滤掉非异常的输出。

import java.util.regex.Pattern;  class HookExample {  public static void main(String[] args) {  String commitMsg = args[0];  boolean checkIssueId = Pattern.matches("^#\\d+\\s+.*", commitMsg);  if(!checkIssueId) {  System.out.println("fail: commit msg 必须在开头添加 issue id");  }  }  
}

结语

虽然这是一篇编写自定义 Git Hook 的教程,但实际讲的仍然是编写脚本的问题,除了用于编写 git hook, 我们平日里还可以通过编写脚本的方式来代替无意义、重复的工作,例如创建模板代码、数据处理、文件管理、生成 mock 数据、定时执行任务等等,再或者我们可以在脚本中发起请求,直接通过命令方式获取某些数据进一步处理等等。

通过编写脚本解决日常重复性工作可以提高效率和减少人为错误,当遇到一些重复性高、繁琐的工作任务时,编写脚本来处理这些任务可以节省时间和精力。

此外,脚本还可以提高工作的准确性和一致性,由于脚本是按照预先定义的规则和流程执行的,因此可以避免人为操作带来的错误和不一致性。这对于需要高度精确和一致性的工作任务尤为重要。

当然了,通过编写脚本实现工具代替某些工作有时也会适得其反,比如某些工作明明人工操作可能仅需要一两个小时,但编写脚本可能要花半天时间,再加上可能存在bug, 这时工具的作用未必理想,所以谨记编写脚本的目的是为了提高效率而不是为了制造麻烦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/699933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ONLYOFFICE桌⾯应⽤程序v8.0:功能丰富,⽀持多平台

文章目录 可填写的 PDF 表单RTL支持电子表格中的新增功能其他改进和新增功能与 Moodle 集成用密码保护 PDF 文件快速创建文档本地界面主题总结 继 ONLYOFFICE 文档 v8.0 的发布后&#xff0c;很高兴&#xff0c;因为适用于 Linux、Windows 和 macOS 的 ONLYOFFICE 桌面应用程序…

【elementUi-table表格】 滚动条 新增监听事件; 滚动条滑动到指定位置;

1、给滚动条增加监听 this.dom this.$refs.tableRef.bodyWrapperthis.dom.scrollTop 0let _that thisthis.dom.addEventListener(scroll, () > {//获取元素的滚动距离let scrollTop _that.dom.scrollTop//获取元素可视区域的高度let clientHeight this.dom.clientHeigh…

Matlab/simulink基于MPPT风光储微电网建模仿真(持续更新)

​ 2.Matlab/simulink基于MPPT风光储微电网建模仿真&#xff08;持续更新&#xff09; 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

QT 打包命令 windeployqt 在windows平台应用

本文以qt6.2.4 MSVC2019 为例&#xff0c;描述打包过程。 前置条件&#xff1a;已经生成了可执行文件&#xff0c;比如xxx.exe 1.在搜索框输入QT,点击QT6.2.4(MSVC 2019 64-bit) 以你实际安装的版本为准。 2.出现如下黑屏命令行 3.在QT 项目文件下新建一个打包文件夹&#x…

VIO第2讲:IMU标定实验

VIO第2讲&#xff1a;IMU标定实验 文章目录 VIO第2讲&#xff1a;IMU标定实验5 IMU标定实验5.1 仿真数据产生5.1.1 c代码分析5.1.2 生成ros包数据 5.2 Allan方差实验&#xff08;港科大imu_utils&#xff09;5.2.1 安装5.2.2 运行 5.3 Allan方差实验&#xff08;matlab代码kali…

Vue局部注册组件实现组件化登录注册

Vue局部注册组件实现组件化登录注册 一、效果二、代码1、index.js2、App.vue3、首页4、登录&#xff08;注册同理&#xff09; 一、效果 注意我这里使用了element组件 二、代码 1、index.js import Vue from vue import VueRouter from vue-router import Login from ../vie…

基于SVM的功率分类,基于支持向量机SVM的功率分类识别,Libsvm工具箱详解

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 完整代码和数据下载链接:基于SVM的功率分类,基于支持向量机SVM的功率分类识别资源-CSDN文库 https://download.csdn.net/download/abc991835105/88862836 SVM应用实例, 基于…

虚拟机的四种网络模式对比

nat网络地址转换 nat网络 桥接 内网模式 仅主机

【Java】java异常处理机制(实验五)

目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 1、理解java的异常处理机制 2、掌握try catch结构和thow和thows关键字的用法 二、实验内容 1、编写一个程序&#xff0c;输入某个班某门课程成绩&#xff0c;统计及格人数、不及格人数及课程平均分。设计一个异…

通天星CMSV6 车载视频监控平台信息泄露漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【Python-语法】

Python-语法 ■ Python基础■ 数据类型■ 注释 单行注释&#xff0c;多行注释■ 编码方式 ■■■■■ ■ Python基础 ■ 数据类型 ■ 注释 单行注释&#xff0c;多行注释 ■ 编码方式 ■ ■ ■ ■ ■

【深度学习】微调通义千问模型:LoRA 方法,微调Qwen1.8B教程,实践

官网资料: https://github.com/QwenLM/Qwen/blob/main/README_CN.md 文章目录 准备数据运行微调设置网络代理启动容器执行 LoRA 微调修改 finetune/finetune_lora_single_gpu.sh运行微调 执行推理 在本篇博客中&#xff0c;我们将介绍如何使用 LoRA 方法微调通义千问模型&#…

Unity 2021.3发布WebGL设置以及nginx的配置

使用unity2021.3发布webgl 使用Unity制作好项目之后建议进行代码清理&#xff0c;这样会即将不用的命名空间去除&#xff0c;不然一会在发布的时候有些命名空间webgl会报错。 平台转换 将平台设置为webgl 设置色彩空间压缩方式 Compression Format 设置为DisabledDecompre…

Sora:开启视频生成新时代的强大人工智能模型

目录 一、Sora模型的诞生与意义 二、Sora模型的技术特点与创新 三、Sora模型的应用前景与影响 四、面临的挑战与未来发展 1、技术挑战 2、道德和伦理问题 3、计算资源需求 4、未来发展方向 随着信息技术的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已成为…

vue3中使用vuedraggable实现拖拽el-tree数据进分组

看效果&#xff1a; 可以实现单个拖拽、双击添加、按住ctrl键实现多个添加&#xff0c;或者按住shift键实现范围添加&#xff0c;添加到框中的数据&#xff0c;还能拖拽排序 先安装 vuedraggable 这是他的官网 vue.draggable中文文档 - itxst.com npm i vuedraggable -S 直接…

拓扑空间简介

目录 介绍集合论与映射映射相关定义映射&#xff08;map&#xff09;映射的一种分类&#xff1a;一一的和到上的 拓扑空间背景介绍开子集开子集的选择 拓扑拓扑空间常见拓扑拓扑子空间同胚其他重要定义 开覆盖紧致性有限开覆盖紧致性 R R R的紧致性 习题 介绍 这是对梁灿彬的《…

【软件架构】01-架构的概述

1、定义 软件架构就是软件的顶层结构 RUP&#xff08;统一过程开发&#xff09;4 1 视图 1&#xff09;逻辑视图&#xff1a; 描述系统的功能、组件和它们之间的关系。它主要关注系统的静态结构&#xff0c;包括类、接口、包、模块等&#xff0c;并用于表示系统的组织结构…

C++入门学习(三十六)函数的声明

程序是自上而下运行的&#xff0c;比如我下面的代码&#xff1a; #include <iostream> #include<string> using namespace std;int main() { int a1; int b2;int sumaddNumbers(a,b); cout<<sum;return 0; }int addNumbers(int a, int b) { int sum …

MFC 配置Halcon

1.新建一个MFC 工程&#xff0c;Halcon 为64位&#xff0c;所以先将工程改为x64 > VC 目录设置包含目录和库目录 包含目录 库目录 c/c ->常规 链接器 ->常规 > 链接器输入 在窗口中添加头文件 #include "HalconCpp.h" #include "Halcon.h"…

简单讲解并梳理微信小程序默认几个文件和文件夹结构及其作用

那么 我们来说一下 小程序整个项目结构 它各个文件 和 整体结构 这是我们新创建的一个小程序项目 我们从上到下 分别来看一下 这些文件和目录结构的作用 首先是 pages 它的作用在于存储整个项目所有的 page页面文件 我们小程序官方 是推荐我们将所有page 界面都放在pages目录…