Clean Commits from the Start with pre-commit
Have you ever run git commit, only to realize later that you forgot to remove a stray debug statement or fix a small formatting error? If so, you know how frustrating it is to catch that mistake only after you have pushed your changes. These tiny missteps can quickly add up to big hassles for your entire team. That is why a simple tool called pre-commit can be so helpful. It automatically runs checks, linters, and other automated routines right before you commit your code, helping you catch common slip-ups before they make it into your repository.
What is pre-commit?
pre-commit is an open source framework that runs small checks (called “hooks”) on your code when you attempt to commit via Git. By setting up these hooks, you can automate many tasks: enforcing coding style, scanning for security issues, fixing trailing whitespace, and more. The moment you type git commit, pre-commit checks your changes. If anything does not pass the checks, pre-commit prevents the commit from completing. This keeps your repository clean and consistent from the very beginning.
Why pre-commit instead of other options?
There are several ways to achieve automated checks, including writing your own Git hooks, using a separate linting utility, or even relying entirely on a continuous integration (CI) server to catch coding problems. pre-commit, however, stands out by making it easy to configure and share these checks. You simply add a .pre-commit-config.yaml file to your repository and specify which checks you want. Anyone who clones your repository can run pre-commit install to use the same checks locally. This is simpler than manually writing your own Git hooks, and it can catch errors much earlier than waiting for a CI build to fail. For background on Git hooks, you can explore git-scm’s official documentation.
Example: how pre-commit works
Suppose you want to ensure that your Python code does not contain leftover print statements. You can configure pre-commit with a hook that checks for these. Create a file named .pre-commit-config.yaml in your repository, and add something like:
repos:
repo: local hooks:
id: no-print-statements name: No print statements entry: grep -Hn print pass_filenames: true language: system types: [python]
This configuration looks for the word print in Python files. Once you run pre-commit install, every time you commit, pre-commit searches for print statements in your staged code. If it finds them, it stops you from committing until they are removed or commented out.
What are the benefits of using pre-commit?
Faster feedback: You learn about problems the moment you try to commit, which helps prevent mistakes from seeping into your codebase.
Consistency: Because team members share a single configuration file, everyone follows the same set of checks.
Time saved: Tasks like formatting and linting can happen automatically. This can make your pull requests simpler to review, because the style and formatting are already cleaned up.
Simplicity: pre-commit is easy to configure, does not require advanced scripting, and plays nicely with many other tools you might use.
Getting started with pre-commit
You can use pre-commit on a local file, on an entire repo of code, and as part of a CI pipeline
Running pre-commit on a local file
If you want to test pre-commit on just a single file, you can run: pre-commit run --files my_script.py This command tells pre-commit to run its checks on my_script.py only, without a full commit process. It is a quick way to see if a file passes your hooks before you even stage changes. This local file usage is often used when you want to experiment or just test an individual file’s compliance.
Step by step:
Make sure you have pre-commit installed (pip install pre-commit).
Add or update .pre-commit-config.yaml to specify hooks.
Run pre-commit run --files my_script.py to see if your file passes those hooks.
Running pre-commit on an entire repository
Once you have your .pre-commit-config.yaml in the root of your repository:
Install pre-commit on your machine using pip install pre-commit (or whichever method you prefer).
In your repository’s root directory, run pre-commit install. This creates a Git hook script that is triggered whenever you run git commit.
The next time you commit, pre-commit will check every staged file. If there are any errors, pre-commit will stop the commit until those are resolved.
This approach ensures all developers on your team run the same checks. Anyone who clones the repo and runs pre-commit install has the exact same setup. You can even run pre-commit on all files in your repo at once by calling pre-commit run --all-files if you want to do a major cleanup.
Integrating pre-commit as part of a CI pipeline
pre-commit does not have to be limited to local development. Most CI platforms—like GitHub Actions (https://docs.github.com/actions), GitLab CI, and others—can run pre-commit hooks as part of their workflow. In GitHub Actions, for instance, you can:
Create a YAML file in .github/workflows/ (for example, .github/workflows/pre-commit.yml).
Use a pre-built GitHub Action or a simple script step that installs and runs pre-commit.
The CI server will clone your repository, install pre-commit, and run pre-commit run --all-files. If any check fails, the CI job fails, signaling that the pull request needs updates before merging.
Running pre-commit in CI provides an extra layer of security. Even if someone forgets to install or run it locally, the CI process will catch any errors before that code is merged.
Case Studies: pre-commit in the wild
Fin-tech Implementation
Stripe, the payment processing company, uses pre-commit extensively in their open-source projects. Their Python repositories, such as stripe-python, demonstrate sophisticated pre-commit configurations that catch formatting and potential security issues before code review. You can explore their implementation in their GitHub repos.
Open Source Project Management
Major open-source projects have embraced pre-commit for maintaining code quality:
Django Framework:
Official repository uses pre-commit for ensuring code consistency
Configuration available in their GitHub repos.
Flask Project:
Uses pre-commit to standardize contributions
Configuration can be found in GitHub.
Kubernetes Project:
Implements comprehensive pre-commit checks
In summary, pre-commit is a user-friendly, powerful tool for preventing small but irritating mistakes from creeping into your code. By automatically running checks whenever you commit, it keeps your repository consistent and your team aligned. If you have ever endured the pain of discovering a silly bug or style mismatch too late, pre-commit can save you time and head-scratching. It is one of those simple but effective DevOps practices that fosters higher code quality, shorter feedback loops, and smoother collaboration.
If you are looking for even more ways to refine your development workflow, sign up for a free account at Caparra. We build tools and solutions for developers who want to explore DevOps without a lot of heavy jargon. Opening a free account is a quick way to learn more about how to automate tedious tasks, collaborate on code, and start using Caparra’s DevOps resources today: