Introduction
Git can trigger custom scripts when certain important actions occur, among which the more commonly used are: pre-commit
, commit-msg
, pre-push
and other hooks. We can pre-commit
code format validation trigger, the commit-msg
a commit message and submitting user authentication trigger, the pre-push
unit testing, testing E2E trigger operation.
When Git executes git init
for initialization, it will generate a series of hook scripts .git/hooks
From the figure above, you can see that the suffix of each script .sample
. At this time, the script will not be executed automatically. We need to remove the suffix before it will take effect, that is, pre-commit.sample
become pre-commit
take effect.
This article mainly wants to introduce how to write git hooks scripts, and will write two pre-commit
and commit-msg
scripts as examples to help everyone better understand git hooks scripts. Of course, it is recommended to use the ready-made, open source solution husky .
text
There are no restrictions on the scripting language used to write git hooks. You can use nodejs
, shell
, python
, ruby
and other scripting languages, which are very flexible and convenient.
Below I will use shell language to demonstrate how to write pre-commit
and commit-msg
scripts. Also note that when executing these scripts, if you exit the program with a non-zero value, it will interrupt the git submission/push process. So when the verification message/code fails in the hooks script, you can exit with a non-zero value and interrupt the git process.
exit 1
pre-commit
pre-commit
to do in the 060f585731eae4 hook is very simple, only checking the format of the code to be submitted, so the script code is relatively small:
#!/bin/sh
npm run lint
# 获取上面脚本的退出码
exitCode="$?"
exit $exitCode
Since I have configured the relevant eslint configuration and npm script in the project, it is pre-commit
to execute the relevant lint command in 060f585731eb15, and judge whether it exits normally.
// 在 package.json 文件中已配置好 lint 命令
"scripts": {
"lint": "eslint --ext .js src/"
},
Let's look at an animated picture below. When the code format is incorrect, an error will be reported when commit is made:
Submit after modifying the code format, then no error will be reported:
As can be seen from the moving picture, this commit has been submitted normally.
commit-msg
In commit-msg
hooks, we need to verify the commit message and the user.
#!/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
When the commit-msg
hook is triggered, the corresponding script will receive a parameter. This parameter is the commit message, which is obtained through cat $1
and assigned to the commit_msg
variable.
It is relatively simple to verify the regularity of the commit message, just look at the code. If you are interested in commit submission specifications, you can check out my other article .
It is relatively simple to judge user permissions, just check the user's mailbox or user name (assuming that only employees of the abc company have the permission to submit codes).
email_re="@abc\.com"
if [[ ! $email =~ $email_re ]]
then
echo "此用户没有权限,具有权限的用户为: xxx@abc.com"
# 异常退出
exit 1
fi
The following two animations are used to demonstrate the process of verifying commit messages and judging user permissions:
Set the default location of git hooks
The normal execution of the script is only the first step, and there is another problem that must be solved, that is, how to share the git hooks configuration with other developers in the same project. Because the .git/hooks
directory will not be pushed to the remote warehouse along with the submission. There are two solutions to this problem: the first is to imitate husky to make an npm plug-in, and automatically .git/hooks
directory during installation; the second is to write the hooks script separately in a certain directory in the project, and then When the project installs dependencies, this directory is automatically set to the hooks directory of git.
Next, talk about the implementation process of the second method in detail:
- After the
npm install
completed, thegit config core.hooksPath hooks
command is automatically executed. git config core.hooksPath hooks
command sets the git hooks directory to the hooks directory under the project root directory."scripts": { "lint": "eslint --ext .js src/", "postinstall": "git config core.hooksPath hooks" },
Step on the pit
The demo source code can run normally on windows, but it won’t work after changing to a mac, and an error is reported when submitting:
hint: The 'hooks/pre-commit' hook was ignored because it's not set as executable.
The reason is that the hooks script is not executable by default, so you need to make it executable:
chmod 700 hooks/*
In order to avoid having to modify every time the project is cloned, it is best to add this command to the npm script:
"scripts": { "lint": "eslint --ext .js src/", "postinstall": "git config core.hooksPath hooks && chmod 700 hooks/*" },
Of course, if it is windows, there is no need to add the second half of the code.
nodejs hooks script
In order to help front-end students better understand the git hooks script, I used nodejs to rewrite another version.
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);
}
to sum up
In fact, the scope of application of this article is not limited to the front-end, but to all projects that use git as version control. For example, Android, ios, Java, etc. It's just that this article chose the front-end project as an example.
Recently attached project source code: https://github.com/woai3c/git-hooks-demo
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。