Introduction to the

Git can trigger custom scripts when certain important actions occur. Some of the most common examples are pre-commit, commit-msg, pre-push hooks, and so on. We can verify the code format during the pre-commit trigger, verify the COMMIT message and the committed user during the COMMIT – MSG trigger, and conduct unit tests, E2E tests, and other operations during the pre-push trigger.

When Git initializes Git init, it generates a series of hooks scripts in the. Git /hooks directory:

As you can see from the figure above, each script ends with.sample. At this point, the script will not be executed automatically. We need to remove the suffix for this to take effect, so that pre-commit. Sample becomes pre-commit for this to work.

The purpose of this article is to explain how to write git hooks, and to write two pre-commit and commit-msg scripts as examples to help you understand them better. Of course, the off-the-shelf, open source solution Husky is still recommended in your work.

The body of the

There is no limit to the scripting languages you can use to write git hooks. You can use Nodejs, Shell, Python, Ruby, etc., which are very flexible and convenient.

I’ll show you how to write pre-commit and commit-msg scripts in shell language. Also note that when executing these scripts, exiting the program with a non-zero value will interrupt Git’s commit/push process. So if you validate that the message/code in the hooks script is not valid, you can interrupt the Git process with a non-zero exit value.

exit 1

pre-commit

What you do in the Pre-Commit hook is very simple. You only check the format of the code to commit, so the script code is relatively small:

#! /bin/sh NPM run lint exitCode="$?" exit $exitCode

Since I already have the relevant ESLint configuration and the NPM script configured in the project, I can simply execute the relevant lint command on pre-commit and check to see if it exits properly.

// The lint command "scripts": {"lint": "eslint -- ext.js SRC /"} is configured in package.json file,

Here is a GIF where a commit error occurs when the code is not properly formatted:

If you change the format of the code before committing it, it will not report an error:

As you can see from the GIF, this Commit has been committed normally.

commit-msg

In COMMIT – MSG hooks, we need to validate both the COMMIT message and the user.

#! # commit_msg= 'cat $1' # 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 "\ \ \ nFeat: Add comments\ \nfix: Handle events on blur (close #28)\ \n For details see Git Commit specification: https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md "abnormal exit exit # 1 fi

When the commit_msg hook fires, the corresponding script receives a commit_msg message, which is taken through cat $1 and assigned to the commit_msg variable.

Verifying the regularity of the COMMIT message is easy, just look at the code. If you’re interested in the Commit Commit specification, check out my other article.

Determining user permissions is a simple matter of checking the user’s email or username (assuming that only ABC employees now have access to submit code).

Email_re ="@abc\ "if [[! $email =~ $email_re]] then echo

Here are two GIFs to illustrate the process of verifying a COMMIT message and determining user permissions:

Set git hooks to the default location

Getting the script to work is only the first step; there is also the problem of how to share git hooks configurations with other developers on the same project. Because the.git/hooks directory is not pushed to the remote repository along with the commit. There are two possible solutions to this problem. One is to emulate Husky by making an NPM plugin that automatically adds hooks to the. Git /hooks directory when installed. The second is to write hooks scripts separately to a directory in your project and then automatically set that directory to Git’s hooks directory when a dependency is installed on that project.

Here’s how to implement the second method in detail:

  1. innpm installWhen the execution is complete, it is automatically executedgit config core.hooksPath hooksCommand.
  2. The git config core.hooksPath hooks command sets the git hooks directory to the hooks directory at the root of the project.

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

    Hit the pit

    DEMO source code on Windows is able to run normally, but later changed to a Mac after the line is not good.

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

    Because the hooks script is not executable by default, you need to make it executable:

    chmod 700 hooks/*

    To avoid having to change each clone project, 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’s Windows, you don’t need to add the second half of the code.

Nodejs hooks script

In order to help you understand git hooks better, I rewrote it with 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(); // commitRE = const commitRE = /^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))? : {1100} /; if (! commitRE.test(msg)) { console.log(); Console. error(' Invalid Commit message format, please use the correct commit format: '); console.error('feat: add \'comments\' option'); console.error('fix: handle events on blur (close #28)'); Console. Error (' details, please see the git commit to submit specifications: https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md. '); process.exit(1); } if (! /@qq\..com$/.test(email)) {console.error(' This user has no permissions, the user with permissions is: [email protected]'); process.exit(1); }

conclusion

The scope of this article is not limited to the front end, but to any project that uses Git as versioning. Android, iOS, Java, etc. It’s just that this article chose the front-end project as an example.

Recently with the project source code: https://github.com/woai3c/git…

The resources

  • Custom Git – An example of using a mandatory policy
  • Shell tutorial