Configuring Git Hooks with Pre-Commit
September 26, 2021
Overview
Git hooks are scripts that trigger commands at various intervals in git's execution. Git hooks are useful for running checks against local code changes (ie: linting and formatting) before submitting these changes for code review. Pre-commit is a python library for configuring and running langauge-agnostic git hooks at various intervals (pre-commit, pre-push, pre-merge etc).
Installation
To install pre-commit:
pip install pre-commit
Supported Hooks
Git hooks are versatile in that they allow you to execute third-party libraries, thereby supporting a variety of use cases to match your workflow requirements (here is a list of supported hooks). A few python libraries that are useful for linting and formatting include:
pre-commit-hooks
- default hooks to check the format of yaml files, ensure files end in a whitespace, remove trailing whitespaces within files and check the validity of files (Documentation)isort
- a tool to sort import statements alphabetically, and separate packages into sections by type (Documentation)black
- a tool to format your code, compliant with PEP 8 (Documentation)flake8
- a tool to enforce consistent style and linting checks (Documentation)pydocstyle
- a tool to check compliance with Python docstring conventions (Documentation)mypy
- a tool for static type checking built on top of Python type annotations (Documentation)
Configuration
Git hooks are defined in a pre-commit-config.yaml
file in the root directory of a project. For example, using the libraries specified in Supported Hooks, the following configuration may be used:
repos:
- repo: [https://github.com/pre-commit/pre-commit-hooks](https://github.com/pre-commit/pre-commit-hooks)
rev: v4.0.1
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-ast
- repo: [https://github.com/pycqa/isort](https://github.com/pycqa/isort)
rev: 5.10.0
hooks:
- id: isort
- repo: [https://github.com/psf/black](https://github.com/psf/black)
rev: 22.0.0
hooks:
- id: black
- repo: [https://github.com/pycqa/flake8](https://github.com/pycqa/flake8)
rev: 4.0.0
hooks:
- id: flake8
- repo: [https://github.com/python/mypy](https://github.com/python/mypy)
rev: v0.950
hooks:
- id: mypy
- repo: [https://github.com/PyCQA/pydocstyle](https://github.com/PyCQA/pydocstyle)
rev: 6.1.1
hooks:
- id: pydocstyle
You can specifiy the stage you want a hook to run by choosing and installing a relevant hook type (here is a list of hook stages).
To install the environments needed to run git hooks:
pre-commit install --hook-type pre-commit --install-hooks
A seperate environment is created for each hook type and is located in ~/.git/hooks/
.
To update git hooks to their latest versions:
pre-commit autoupdate
Usage
Run Automatically
Once you have configured a pre-commit-config.yaml
file and installed the relvant hook environments, pre-commit
will automatically run on every new commit. Each hook runs as an individual test for that commit and will either succeed or fail. If any hook fails, then the commit will not be made and pre-commit
will try modify the conflicting files.
pre-commit
will try make modifications to your working directory, but your staging table won't be modified. You will need to restage any modifications made by the hooks.
For example, if you add a new feature and commit those changes:
git commit -m "Add feature"
The pre-commit
hooks will be run and the outcome of each test will be described:
Check Yaml....................................(no files to check)Skipped
Fix End of Files..................................................Passed
Trim Trailing Whitespace..........................................Passed
Check AST.....................................(no files to check)Skipped
isort.............................................................Passed
black.............................................................Passed
flake8............................................................Passed
mypy..............................................................Passed
pydocstyle........................................................Passed
[main 146c6c2c] Add feature
1 file changed, 1 insertion(+)
Run Manually
If you want to run the hooks against all files without making a commit, you can run the hooks from the command line. This is useful when adding new hooks or in continuous integration workflows.
pre-commit run --all-files