介绍Git可以在特定重要动作发生时触发自定义脚本,其中比较常用的有:pre-commit、commit-msg、pre-push等钩子(钩子)。我们可以在触发pre-commit时验证代码格式,在触发commit-msg时验证commitmessage和提交用户,在触发pre-push时进行单元测试和e2e测试。Git在执行gitinit进行初始化时,会在.git/hooks目录下生成一系列hooks脚本:从上图中可以看出,每个脚本的后缀都是以.sample结尾的。此时脚本不会自动执行。我们需要把后缀去掉才会生效,也就是把pre-commit.sample改成pre-commit就可以了。本文主要是想介绍如何编写githooks脚本,并会写两个pre-commit和commit-msg脚本作为例子,帮助大家更好的理解githooks脚本。当然,工作中还是推荐使用现成的、开源的解决方案husky。用于编写githooks的脚本语言没有限制。可以使用nodejs、shell、python、ruby等脚本语言,非常灵活方便。下面我将使用shell语言来演示如何编写pre-commit和commit-msg脚本。另请注意,在执行这些脚本时,如果以非零值退出程序,则会中断gitcommit/push过程。因此,当hooks脚本中验证消息/代码失败时,可以以非零值退出,中断git进程。exit1pre-commit在pre-commithook中做的事情很简单,只检查要提交的代码格式,所以脚本代码比较少:#!/bin/shnpmrunlint#得到上面的exitcodescriptexitCode="$?"exit$exitCode由于我已经在项目中配置了相关的eslint配置和npm脚本,所以在pre-commit中执行相关的lint命令,判断是否正常退出即可。//package.json文件中已经配置了lint命令"scripts":{"lint":"eslint--ext.jssrc/"},看下面动图,当代码格式不正确时,commit即可报错:修改代码格式再提交,此时不会报错:从动图可以看出,这次commit已经正常提交了。commit-msg在commit-msg钩子中,我们需要验证提交消息和用户。#!/bin/sh#使用``将命令的输出分配给变量#获取当前提交msgcommit_msg=`cat$1`#获取用户电子邮件email=`gitconfiguser.email`msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?:.{1,100}"if[[!$commit_msg=~$msg_re]]thenecho"\n无效的提交信息提交格式,请使用正确的格式:\\nfeat:添加注释\\nfix:处理模糊事件(close#28)\\n请参考gitcommit提交规范详见:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md"#异常退出exit1fi时触发commit-msghook,相应的script会收到一个参数,这个参数就是commitmessage,由cat$1获取,赋值给commit_msg变量。验证commitmessage的规律性比较简单,看代码即可。如果对commit提交规范感兴趣,可以阅读我的另一篇文章。判断用户权限比较简单,只需要查看用户的邮箱或者用户名即可(假设只有abc公司的员工有提交代码的权限)。email_re="@abc\.com"如果[[!$email=~$email_re]]thenecho"Thisuserhasnopermission,theuserhaspermissionis:xxx@abc.com"#异常退出exit1fi用下面两个动画来演示校验commit消息和判断用户权限的过程:设置githooks的默认位置,让脚本可以正常执行只是第一步,还有一个问题必须要解决,就是如何与同项目的其他开发者共享githooks配置。因为.git/hooks目录不会随着提交一起推送到远程仓库。这个问题有两种解决方法:第一种是模仿husky做一个npm插件,安装时自动将hooks脚本添加到.git/hooks目录下;第二种是将hooks脚本单独写在一个项目目录下,然后在项目安装依赖的时候自动将该目录设置为git的hooks目录。下面详细说说第二种方法的实现过程:执行npminstall后,自动执行gitconfigcore.hooksPathhooks命令。gitconfigcore.hooksPathhooks命令将githooks目录设置为项目根目录下的hooks目录。"scripts":{"lint":"eslint--ext.jssrc/","postinstall":"gitconfigcore.hooksPathhooks"},踩坑demo的源码在windows上可以正常运行,以后改为Itwillnotworkaftermac,提交时报错:hint:The'hooks/pre-commit'hookwasignoredbecauseit'snotsetasexecutable.原因是hooks脚本默认是不可执行的,所以需要设置为可执行:chmod700hooks/*为了避免每次clone的时候都要修改工程,最好加上这条命令npmscript:"scripts":{"lint":"eslint--ext.jssrc/","postinstall":"gitconfigcore.hooksPathhooks&&chmod700hooks/*"}当然,如果是windows,不需要添加后半部分代码。nodejshooks脚本为了帮助前端同学更好的理解githooks脚本,我用nodejs重写了一遍。预提交#!/usr/bin/envnodeconstchildProcess=require('child_process');try{childProcess.execSync('npmrunlint');}catch(error){console.log(error.stdout.toString());process.exit(1);}commit-msg#!/usr/bin/envnodeconstchildProcess=require('child_process');constfs=require('fs');constemail=childProcess.execSync('gitconfiguser.email').toString().trim();constmsg=fs.readFileSync(process.argv[2],'utf-8').trim();//提交索引2对应的消息文件constcommitRE=/^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?:.{1,100}/;if(!commitRE.test(msg)){console.log();console.error('无效的提交消息格式,请使用正确的提交格式:');console.error('feat:添加\'comments\'选项');console.error('fix:处理模糊事件(close#28)');console.error('详细请参考gitcommit提交规范: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作为版本控制的项目。比如android、ios、java等等。只是本文选择前端项目为例。最近附上项目源码:https://github.com/woai3c/git...参考自定义Git-使用强制策略Shell教程的例子
