We’ve all encountered commit messages like test
, modif
, or reran notebook
. These vague messages make navigating the commit history unnecessarily challenging. Additionally, inconsistent file formatting can cause friction in collaborative environments, leading to wasted time resolving trivial issues after commits.
Fortunately, you can proactively address these problems with pre-commit checks, ensuring both commit messages and file formats are correct before they reach your repository.
What are Pre-Commit Checks?
Pre-commit checks are automated scripts executed right before you commit code. They enforce predefined standards, such as file formatting rules (e.g., Python’s Black formatter) and structured commit messages (like Conventional Commits). By catching issues early, pre-commit checks help maintain a clean, readable, and consistent codebase.
Key benefits include:
- Clear and informative commit history
- Uniform formatting across all files
- Reduced time spent troubleshooting trivial issues
Let’s walk through setting up pre-commit checks in your GitHub repository.
Setting Up Pre-Commit Checks
Step 1: Install Pre-Commit
If you’re using Homebrew on macOS, run:
brew install pre-commit
For other operating systems, check the official installation guide.
Step 2: Configure Your Repository
Create two essential files at the root of your repository:
.pre-commit-config.yaml
: Specifies the checks to run..commitlintrc.yaml
: Configures commit message formatting rules.
#.commitlintrc.yaml
extends:
- "@commitlint/config-conventional"
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.4.2
hooks:
- id: commitlint
stages: [commit-msg]
additional_dependencies: ["@commitlint/config-conventional"]
Step 3: Run the checks
Now, when you commit code, these checks will automatically run, ensuring that:
- YAML files are correctly formatted.
- Files end with a newline (necessary for some systems).
- No trailing whitespace remains.
- Commit messages adhere to Conventional Commits.
Try it out with a sample commit:
git add .pre-commit-config.yaml .commitlintrc.yaml
git commit -m "feat: enable pre-commit checks for formatting and commit messages"
Appendix
Conventional Commits Format
The Conventional Commits specification ensures clear commit messaging. The structure is as follows:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Example:
feat(config): allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file now extends other config files
Adding Python Formatting with Black
To integrate Python’s Black formatter, append the following to your .pre-commit-config.yaml
file:
- repo: https://github.com/psf/black
rev: 21.12b0
hooks:
- id: black
title: “Pre-commit Checks to Format Your Files and Commit Messages” date: 2022-06-07 draft: false description: “Stop committing wrongly formatted code and start using pre-commit checks.” tags: [“CI/CD”, “pre-commit”]
Effective commit messages and consistent file formatting greatly enhance collaboration and productivity in software projects. Instead of struggling with unclear commit messages like test
, modif
, or reran notebook
, or wasting time fixing formatting issues post-commit, you can proactively ensure clarity and consistency before any code gets committed.
This is where pre-commit checks come into play. These checks automatically enforce formatting standards (such as Python’s Black formatter) and commit message conventions (like Conventional Commits) at the time of committing. By catching issues early, they help prevent vague commit messages and formatting inconsistencies.
In essence, pre-commit checks streamline your development workflow, reducing unnecessary follow-up commits and improving the readability and maintainability of your project’s history.
Let’s explore how you can easily implement these valuable practices in your GitHub repository. (If you’re unfamiliar with Conventional Commits, refer to the appendix first, then return here.)
Get started with pre-commit checks
Step 1: Install pre-commit
To install pre-commit, simply run
brew install pre-commit
This will install pre-commit on your machine.
Step 2: Add pre-commit checks to your repo
To be able to add pre-commit checks that make sure your files and commit messages are correctly formatted, you simply need to add 2 files at the root of your repo:
- .pre-commit-config.yaml: defines the checks you want to run
- .commitlintrc.yaml: defines the npm package you use for pre commits.
# .commitlintrc.yaml
extends:
- "@commitlint/config-conventional"
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v8.0.0
hooks:
- id: commitlint
stages: [commit-msg]
additional_dependencies: ["@commitlint/config-conventional"]
Once you added those files, you can try adding a commit, the pre commit checks defined will make sure that:
- yaml files are correctly formatted
- files have an extra empty line at the end (this is considered best practice as some systems fail when this condition is not met)
- get rid of trailing whitespaces
- make sure that the commits follow the conventional commits format.
To see if this worked, try to commit those files to your repo with some commit message like git commit -m ‘feat: enabled pre-commit checks’
Apendix
Appendix 1: A word on Conventional Commits With conventional commits, the commit message should be structured as follows:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
For example (from commit conventional docs):
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
Appendix 2: adding a python code formatter to pre-commit checks. If you want to add a python code formatter, like black, you can append to the end of .pre-commit-config.yaml
- repo: https://github.com/psf/black
rev: 21.12b0
hooks:
- id: black