What is a Git Hook?
Git hooks are script files that can be executed in response to specific events or operations. They can be classified into two distinct categories: client-side hooks and server-side hooks.
How to create a Git Hook
Git hooks are located within the .git/hooks
directory. During the initialization of a repository using git init
, a set of example hooks is generated, covering various types of hooks. These examples are suffixed with .sample
, and in order to utilize them, the suffix must be removed. The provided examples are predominantly written as shell scripts, incorporating some Perl, but any appropriately named executable scripts can be used—be it Ruby, Python, or any other language you are familiar with.
Each hook possesses its own unique interpretation, necessitating a review of the provided examples or documentation to determine whether specific parameters are required, if a return value is expected, and other relevant specifications.
List of Git Hooks
applypatch.msg
: Check the commit log taken by applypatch from an e-mail message. This script can modify the commit message. Exit with a non-zero status to stop the commit.post-update
: Prepare a packed repository for use over dump transports.pre-applypatch
: This script is executed before theapplypatch
hook.prepare-commit-msg
: This hook is called withgit commit
and it is used to prepare the commit message. It receives two parameters: the name of the file that has the changes and the description of the commit. If the script returns a non-zero status, the commit will be abortedcommit-msg
: Called with one argument, the name of the file that has the commit message. This script can modify the commit message. Exit with a non-zero status to stop the commit.pre-commit
: This hooks is executed when you usegit commit
command. It takes no arguments but it is useful to pause the commit returning a non-zero status with a message. E.g: stop the commit if the code is not properly formatted or stop the commit if tests are failing.post-commit
: It runs once thegit commit
is finished. It does not take any argument and it is usually used to provide custom messages.pre-merge-commit
: This hook is executed when you are about to perform agit merge
operation. It takes no arguments and should return a non-zero status to stop a merge.pre-push
: This hooks is executed when you perform agit push
command. After checking the remote status, but before pushing anything. It takes two arguments: name of the remote branch and the URL to which the push will be done. If this script retun a non-zero status, it will stop the push.pre-rebase
: This hooks is executed beforegit rebase
is started. It takes two arguments: the upstream the series was forked from and the branch being rebased (or empty when rebasing the current branch). If it returns a non-zero status, the rebase will be aborted.post-checkout
: Executed after a successfulgit checkout
.
Check the complete list in the next url: Official list with all the git hooks
Setup Git Hooks with Rust
A wide range of freely available crates exists to enhance the implementation of git hooks in Rust projects. Personally, I have chosen to utilize the rusty-hook
crate.
There are two methods for incorporating this crate into our project. The first approach involves adding it as a dev dependency in our Cargo.toml
file. Upon building the project for the first time, it will be automatically initialized:
[dev-dependencies]
rusty-hook = "^0.11.2"
Or install and initialize it:
cargo install rusty-hook
rusty-hook init
How to use it
Once the crate is initialized we will be able to see new file named .rusty-hook.toml
at the root of our project. This file is the only thing we need to work with rusty-hook.
The first time we open the file everything is already set up.
[hooks]
pre-commit = "cargo test"
[logging]
verbose = true
Under the [hooks]
section, we have the ability to assign a custom script that will be executed for a specific git hook. The following example, extracted from a personal project, showcases a script that formats the code, runs clippy (a Rust linter), and executes all tests in the project before committing the staged changes.
[hooks]
pre-commit = "cargo fmt && git add . && cargo check && cargo test && cargo test --workspace -- --include-ignored --show-output && cargo clippy"
pre-push = "cargo fmt -- --check || cargo fmt && cargo fmt -- --check"