热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用husky统一管理githooks,实现gitcommit之前校验eslint,通过才能commit成功

简介Git能在特定的重要动作发生时触发自定义脚本,其中比较常用的有:pre-commit、commit-msg、pre-push等钩子(hooks)。我们可以在pre-commit

简介

Git 能在特定的重要动作发生时触发自定义脚本,其中比较常用的有:pre-commitcommit-msgpre-push 等钩子(hooks)。我们可以在 pre-commit 触发时进行代码格式验证,在 commit-msg 触发时对 commit 消息和提交用户进行验证,在 pre-push 触发时进行单元测试、e2e 测试等操作。

Git 在执行 git init 进行初始化时,会在 .git/hooks 目录生成一系列的 hooks 脚本:

从上图可以看到每个脚本的后缀都是以 .sample 结尾的,在这个时候,脚本是不会自动执行的。我们需要把后缀去掉之后才会生效,即将 pre-commit.sample 变成 pre-commit 才会起作用。

本文主要是想介绍一下如何编写 git hooks 脚本,并且会编写两个 pre-commitcommit-msg 脚本作为示例,帮助大家更好的理解 git hooks 脚本。当然,在工作中还是建议使用现成的、开源的解决方案 husky。


正文

用于编写 git hooks 的脚本语言是没有限制的,你可以用 nodejsshellpythonruby等脚本语言,非常的灵活方便。

下面我将用 shell 语言来演示一下如何编写 pre-commitcommit-msg 脚本。另外要注意的是,在执行这些脚本时,如果以非零的值退出程序,将会中断 git 的提交/推送流程。所以在 hooks 脚本中验证消息/代码不通过时,就可以用非零值进行退出,中断 git 流程。

exit 1

pre-commit

pre-commit 钩子中要做的事情特别简单,只对要提交的代码格式进行检查,因此脚本代码比较少:

#!/bin/sh
npm run lint
# 获取上面脚本的退出码
exitCode="$?"
exit $exitCode

由于我在项目中已经配置好了相关的 eslint 配置以及 npm 脚本,因此在 pre-commit 中执行相关的 lint 命令就可以了,并且判断一下是否正常退出。

// 在 package.json 文件中已配置好 lint 命令
"scripts": {
"lint": "eslint --ext .js src/"
},

下面看一个动图,当代码格式不正确的时候,进行 commit 就报错了:

在修改代码格式后再进行提交,这时就不报错了:

从动图中可以看出,这次 commit 已正常提交了。


commit-msg

commit-msg hooks 中,我们需要对 commit 消息和用户进行校验。

#!/bin/sh
# 用 `` 可以将命令的输出结果赋值给变量
# 获取当前提交的 commit msg
commit_msg=`cat $1`
# 获取用户 email
email=`git config user.email`
msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
if [[ ! $commit_msg =~ $msg_re ]]
then
echo "\n不合法的 commit 消息提交格式,请使用正确的格式:\
\nfeat: add comments\
\nfix: handle events on blur (close #28)\
\n详情请查看 git commit 提交规范:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md"
# 异常退出
exit 1
fi

commit-msg 钩子触发时,对应的脚本会接收到一个参数,这个参数就是 commit 消息,通过 cat $1 获取,并赋值给 commit_msg 变量。

验证 commit 消息的正则比较简单,看代码即可。如果对 commit 提交规范有兴趣,可以看看我另一篇文章。

对用户权限做判断则比较简单,只需要检查用户的邮箱或用户名就可以了(假设现在只有 abc 公司的员工才有权限提交代码)。

email_re="@abc\.com"
if [[ ! $email =~ $email_re ]]
then
echo "此用户没有权限,具有权限的用户为: xxx@abc.com"
# 异常退出
exit 1
fi

下面用两个动图来分别演示一下校验 commit 消息和判断用户权限的过程:


设置 git hooks 默认位置

脚本可以正常执行只是第一步,还有一个问题是必须要解决的,那就是如何和同一项目的其他开发人员共享 git hooks 配置。因为 .git/hooks 目录不会随着提交一起推送到远程仓库。对于这个问题有两种解决方案:第一种是模仿 husky 做一个 npm 插件,在安装的时候自动在 .git/hooks 目录添加 hooks 脚本;第二种是将 hooks 脚本单独写在项目中的某个目录,然后在该项目安装依赖时,自动将该目录设置为 git 的 hooks 目录。

接下来详细说说第二种方法的实现过程:



  1. npm install 执行完成后,自动执行 git config core.hooksPath hooks 命令。

  2. git config core.hooksPath hooks 命令将 git hooks 目录设置为项目根目录下的 hooks 目录。

"scripts": {
"lint": "eslint --ext .js src/",
"postinstall": "git config core.hooksPath hooks"
},

踩坑

demo 源码在 windows 上是可以正常运行的,后来换成 mac 之后就不行了,提交时报错:

hint: The 'hooks/pre-commit' hook was ignored because it's not set as executable.

原因是 hooks 脚本默认为不可执行,所以需要将它设为可执行:

chmod 700 hooks/*

为了避免每次克隆项目都得修改,最好将这个命令在 npm 脚本上加上:

"scripts": {
"lint": "eslint --ext .js src/",
"postinstall": "git config core.hooksPath hooks && chmod 700 hooks/*"
},

当然,如果是 windows 就不用加后半段代码了。


nodejs hooks 脚本

为了帮助前端同学更好的理解 git hooks 脚本,我用 nodejs 又重写了一版。

pre-commit

#!/usr/bin/env node
const childProcess = require('child_process');
try {
childProcess.execSync('npm run lint');
} catch (error) {
console.log(error.stdout.toString());
process.exit(1);
}

commit-msg

#!/usr/bin/env node
const childProcess = require('child_process');
const fs = require('fs');
const email = childProcess.execSync('git config user.email').toString().trim();
const msg = fs.readFileSync(process.argv[2], 'utf-8').trim(); // 索引 2 对应的 commit 消息文件
const commitRE = /^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}/;
if (!commitRE.test(msg)) {
console.log();
console.error('不合法的 commit 消息格式,请使用正确的提交格式:');
console.error('feat: add \'comments\' option');
console.error('fix: handle events on blur (close #28)');
console.error('详情请查看 git commit 提交规范:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md。');
process.exit(1);
}
if (!/@qq\.com$/.test(email)) {
console.error('此用户没有权限,具有权限的用户为: xxx@qq.com');
process.exit(1);
}

总结

其实本文适用的范围不仅仅局限于前端,而是适用于所有使用了 git 作为版本控制的项目。例如安卓、ios、Java 等等。只是本文选择了前端项目作为示例。

 

作者:谭光志
链接:https://juejin.cn/post/6986426226248253476
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



推荐阅读
  • 设计模式详解:模板方法模式的应用与实现
    模板方法模式是一种行为设计模式,通过定义一个操作中的算法骨架,将具体步骤的实现延迟到子类中。本文详细解析了模板方法模式的类图结构、实现方式以及挂钩机制,并结合实际案例进行了深入探讨。此外,文章还提供了丰富的参考资料,帮助读者更好地理解和应用这一设计模式。对于手机用户,建议横屏阅读以获得更佳的阅读体验。 ... [详细]
  • 寒假作业解析:第三周 2月12日 第7题
    尽快完成之前的练习任务!每日一练2.1 Problem A Laurenty and Shop 的题目要求是选择两条不同的路线以最小化总的等待时间。简要分析:通过对比不同路线的等待时间,可以找到最优解。此问题可以通过动态规划或贪心算法来解决,具体取决于路线的复杂性和约束条件。 ... [详细]
  • Node.js 教程第五讲:深入解析 EventEmitter(事件监听与发射机制)
    本文将深入探讨 Node.js 中的 EventEmitter 模块,详细介绍其在事件监听与发射机制中的应用。内容涵盖事件驱动的基本概念、如何在 Node.js 中注册和触发自定义事件,以及 EventEmitter 的核心 API 和使用方法。通过本教程,读者将能够全面理解并熟练运用 EventEmitter 进行高效的事件处理。 ... [详细]
  • 在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转
    本文探讨了在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转的技术细节。通过详细分析Swscale的工作原理和实际应用,展示了如何在Android环境中高效地进行图像格式转换。此外,还介绍了FFmpeg的全平台编译过程,包括x264和fdk-aac的集成,并在Ubuntu系统中配置Nginx和Nginx-RTMP-Module以支持直播推流服务。这些技术的结合为音视频处理提供了强大的支持。 ... [详细]
  • Codeforces 605C:Freelancer's Dreams —— 凸包算法解析与题解分析 ... [详细]
  • 在探讨P1923问题时,我们发现手写的快速排序在最后两个测试用例中出现了超时现象,这在意料之中,因为该题目实际上要求的是时间复杂度为O(n)的算法。进一步研究题解后,发现有选手使用STL中的`nth_element`函数成功通过了所有测试点。本文将详细分析这一现象,并提出相应的优化策略。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • 在探讨 MySQL 正则表达式 REGEXP 的功能与应用之前,我们先通过一个小实验来对比 REGEXP 和 LIKE 的性能。通过具体的代码示例,我们将评估这两种查询方式的效率,以确定 REGEXP 是否值得深入研究。实验结果将为后续的详细解析提供基础。 ... [详细]
  • 本文探讨了利用JavaScript实现集合的对称差集算法的方法。该算法旨在处理多个数组作为输入参数,同时保留每个数组中元素的原始顺序。算法不会移除单个数组内的重复元素,但会删除在不同数组之间出现的重复项。通过这种方式,能够有效地计算出多个数组的对称差集。 ... [详细]
  • 本文探讨了如何通过检测浏览器类型来动态加载特定的npm包,从而优化前端性能。具体而言,仅在用户使用Edge浏览器时加载相关包,以提升页面加载速度和整体用户体验。此外,文章还介绍了实现这一目标的技术细节和最佳实践,包括使用User-Agent字符串进行浏览器识别、条件加载策略以及性能监控方法。 ... [详细]
  • 如何在自建VPS与Coding.net之间选择合适的Git托管方案? ... [详细]
  • MySQL性能优化与调参指南【数据库管理】
    本文详细探讨了MySQL数据库的性能优化与参数调整技巧,旨在帮助数据库管理员和开发人员提升系统的运行效率。内容涵盖索引优化、查询优化、配置参数调整等方面,结合实际案例进行深入分析,提供实用的操作建议。此外,还介绍了常见的性能监控工具和方法,助力读者全面掌握MySQL性能优化的核心技能。 ... [详细]
  • 本文探讨了在Linux 2.6内核中实现进程隐藏的技术方法与实践。通过分析系统调用 `sys_getdents` 的工作原理,提出了一种有效的方法来隐藏指定的进程。该方法通过对内核模块进行修改,拦截并过滤掉目标进程的相关信息,从而在常用的进程查看命令(如 `ps` 和 `top`)中无法显示这些隐藏的进程。实验结果表明,该方法在实际应用中具有较高的隐蔽性和稳定性。 ... [详细]
  • 本文深入探讨了 `ExpressionChangedAfterItHasBeenCheckedError` 错误的原因及其解决方案。通过分析 Angular 的变更检测机制,详细解释了该错误的发生条件,并提供了多种有效的应对策略,帮助开发者在实际开发中避免这一常见问题。 ... [详细]
author-avatar
无梗啦_671
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有