关于前端:手写-git-hooks-脚本precommitcommitmsg

3次阅读

共计 3677 个字符,预计需要花费 10 分钟才能阅读完成。

简介

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://github.com/woai3c/git…

参考资料

  • 自定义 Git – 应用强制策略的一个例子
  • Shell 教程
正文完
 0