Git Hooks

Git Hooks

Hooks in Git are?executable scripts?that are triggered when certain events happen in Git. It's a way to customize Git's internal behaviour, automate tasks, enforce policies, and bring consistency across the team.

For example, hooks can check that passwords or access tokens are not committed, validate that commit messages conform to an agreed format, prevent unauthorized developers from pushing to a branch,?update local directories after a checkout,?and so on.

Git supports both client-side and server-side hooks. Hooks can be written in any programming language though it's common to use Bash, Perl, Python or Ruby.?

What use cases can benefit from Git Hooks?

No alt text provided for this image

The figure illustrates local add/commit followed by a push to the remote repository. Also shown are the relevant hooks. Each hook is given a specific name. Hooks are invoked?by naming convention?before or after specific events.

The?pre-commit?hook is called when the commit procedure begins. This hook can format the code against the project's styling guide, run linting or execute unit tests.?By checking for missing semicolons, trailing whitespace, and debug statements code reviews can focus on more important issues.??Hooks?prepare-commit-msg?and?commit-msg?can be used to format/validate the commit message.

After a successful commit, the hook?post-commit?could be used to send notifications. More commonly, when collaboration is via a remote repository, notifications are sent from the?post-receive?hook that's triggered after all references are updated.?This hook can also deploy the latest changes to production.??The?update?hook that runs once per branch can be used to enforce access control, that is, only authorized users can push to a branch.

What are client-side and server-side hooks?

No alt text provided for this image

Client-side hooks run on developer machines whereas server-side hooks run on the server that hosts the repository. Committing, merging, rebasing, applying patches, and checkout are common Git operations that developers do on their development machines. Any of these commands can trigger their relevant client-side hooks. Server-side hooks are triggered by the?git-receive-pack?command, which is a result of developers pushing changes to the remote repository on a cloud-hosted Git server.

Developers have full control of client-side hooks. Developers can choose to disable all client-side hooks if they wish. If a project's best practices need to be strictly enforced, server-side hooks are the way to do it.

Some Git repository providers impose restrictions on the use of server-side hooks on their cloud-based servers. For example, GitHub's free tier doesn't allow developers to define server-side hooks though GitHub Enterprise Server supports them.?However, there are alternatives to achieve server-side automation such as webhooks, GitHub Apps/Actions, GitLab?CI/CD, GitLab push rules, etc.

  • What are?pre-?and?post-?Git Hooks?
  • Client-side and server-side hooks can be either?pre-?and?post-?hooks. The?pre-?hooks can be used to validate stuff before allowing the requested operation.?For example,?pre-commit?hook executes at the start of a commit workflow. If the commit is deemed invalid for any reason, the hook can return a non-zero value. This terminates the commit operation. By returning zero, the hook states that the commit operation can continue, including the execution of other relevant hooks.
  • The?post-?hooks execute after the requested operation is done. Such a hook's return value doesn't matter since the operation is already complete.??For example,?post-commit?executes after a successful commit. These hooks are typically used to send emails or other notifications.?They may also be used to trigger?CI/CD?pipelines. For example,?post-receive?could be used to deploy the updated code to production.
  • What options help skip the execution of hooks?
  • It's possible to skip some hooks if their associated commands are called with certain options. Hooks?pre-commit,?pre-merge-commit,?prepare-commit-msg, and?commit-msg?can be skipped if?commit?and?merge?commands are invoked with?--no-verify?option.
  • The hook?post-checkout?can be skipped if?clone?and?worktree add?commands are called with?--no-checkout?option. However, this hook is always called for?checkout?and?switch?commands.
  • What essentials should a developer know to use Git Hooks?
  • By default, hooks are stored in?.git/hooks?within the project's repository. Git populates this folder with sample scripts that developers can use as a starting point. However, the file suffix?.sample?must be removed and scripts must be made executable.?Developers can rewrite the scripts in their preferred language. Accordingly, the shebang (#!?first line in script) must be updated with the correct path to the language.
  • If these sample scripts are deleted by mistake, we can retrieve them from Git templates folder. This may be?/usr/local/git-core/templates/hooks?(Linux) or?C:\Program Files\Git\mingw64\share\git-core\templates\hooks?(Windows).?In fact, this copying from templates folder to the project's?.git/?folder is what happens when we run?git init.?
  • While hooks are triggered in response to specific events, we can also manually trigger the execution of a hook. The command for this is?git hook run <hook-name> <hook-args>. For example, we could trigger one hook from another hook.?This command is a low-level internal helper command.
  • Beginners can start by reading the?official documentation on Git Hooks?and Chapter 14 of?Loeliger's book on Git.
  • What does it take to create and maintain reusable Git Hooks?
  • It's a good practice to commit hooks as part of the repository so that all developers reuse and execute the same hooks. However, it's not permitted to store them within a?.git/hooks?folder within the repository. One approach is store them in another folder, say?hooks, and then create a soft link from?.git/hooks?to?hooks?folder after cloning the repository.?Another approach is to configure the path to the hooks with the command?git config core.hooksPath <path>.
  • To reuse across projects, hooks can be in a separate repository and cloned locally. Configure the hooks path globally to that folder:?git config --global core.hooksPath <path>. This configuration variable has been available since Git version 2.9.0.
  • There's also a framework named?pre-commit?to manage pre-commit hooks.?This framework includes?dozens of tested pre-commit hooks written in Python?that developers can reuse in their own projects. These include syntax checking (check-json,?check-yaml), fixing problems (fix-byte-order-marker,?trailing-whitespace), protecting secrets (detect-private-key,?detect-aws-credentials), enforcing policies (no-commit-to-branch,?forbid-new-submodules), and more.
  • The?githooks.com?lists many useful hooks and related tools that developers can use.
  • How do I configure my project environment to use Git Hooks?
  • No special configuration is needed other than updating?.git/hooks?folder or configuring?core.hooksPath?variable. However, many developer tools attempt to simplify this further.
  • In Maven, a plugin can setup the hooks path. In Gradle, we can have a dependent build script to do this setup.?In Node.js, Husky project allows us to wire up all the hooks in the?package.json?file. In PHP, hooks can be set up in?composer.json?file via the?post-install-cmd?configuration.
  • In different languages, frameworks are available to manage hooks: pre-commit (Python), Overcommit (Ruby), Lefthook (Ruby or Node.js).
  • What are some criticisms of Git Hooks?
  • Hooks change Git's default behaviour. If a hook does something unusual, it may confuse developers new to the project. Moreover, hooks can be buggy and make things counterproductive. For this reason, some recommend using Git aliases and invoking scripts directly rather than relying on hooks.
  • Git doesn't provide any easy mechanism to share hooks among developers or from one repository to another. No doubt this is more secure but at the expense of convenience and reusability.?Hooks problem with installation, maintainability, and reusability is to some extent solved by frameworks such as?pre-commit.
  • Hooks are powerful. Developers may be tempted to run unit tests before each commit. This can slow things quite a bit and discourage developers from committing often. This can lead of data loss.
  • Server-side hooks are not universally enabled by cloud-hosted Git repository service providers.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了