Automating PEP 8 Style Checks with Git Pre-commit Hooks
A Git pre-commit hook is a script that runs automatically before each commit and can block the commit if a check fails. This post sets up pre-commit hooks with Python linters to enforce PEP 8 code style automatically before files are committed.
Coding can be hectic and also requires adhering to code styles. For instance, it is a good practice to comply with the PEP 8 guidelines for Python code. PEP 8 is the official Python style guide that establishes rules about variable names, commenting, indentation, and whitespace usage. Following PEP 8 produces easy-to-read, reusable code, which is essential when collaborating with other programmers.
While PEP 8 is a standard, some tools can help us check and fix style issues automatically. Flake8 is one such tool (alongside others such as Pylint and PyLama) that inspects code for PEP 8 compliance errors โ see Flake8: Your Tool For Style Guide Enforcement. These tools are called linters. In this post, we use Git hooks and pre-commit for a simple setup that checks Python code before committing files into the repository.
Python Linters: Flake8 for PEP 8 Compliance
A linter is a static-analysis tool that checks source code for syntax errors and style violations without executing it. Linters ensure code quality in the following aspects:
- ensure correct code formatting and style;
- minimise syntax errors;
- help in code reviews;
- save development time.
Flake8 is a Python linter that is easy to install with pip. Pip is the standard package manager for Python; if you need guidance on installing it, read the article at realpython.com. Since you are reading this post, you most likely already have pip on your system.
# define which Python version you want to install flake8 for
python<version> -m pip install flake8
To use Flake8, run it on a specific file or directory.
# Run Flake8 on repo directory
flake8 path/repo
# Run Flake8 on the file main.py
flake8 path/repo/main.py
Code Formatters: Black for Automatic PEP 8 Formatting
Black is an opinionated Python code formatter that rewrites source files to a deterministic PEP 8-compliant style. You can use Black alone or together with Flake8. As stated on the Black website, Black requires Python > 3.6.2 and is installed with pip.
pip install black
The usage is similar to Flake8; just feed in the project directory or file.
black <file_or_directory>
Black reformats Python files following PEP 8 guidelines, while Flake8 checks for syntax and style errors. Using them together is good practice, and they work well in tandem. Refer to the docs โUsing Black with other toolsโ for more details on Blackโs compatibility with Flake8 and other linters.
Git Hooks and the pre-commit Framework
pre-commit is a framework for managing and running Git hooks that checks and reformats code before it is committed to the repository. The pre-commit package performs these checks automatically while running Git commits. See the official pre-commit documentation for the full hook catalogue.
Installing pre-commit in a Git Repository
To install pre-commit in your Git repository folder, run the following commands.
# Install pre-commit
pip install pre-commit
# Install git hooks in your .git/ directory
pre-commit install
Configuring .pre-commit-config.yaml for Black and Flake8
To configure the hooks we want to include, we define the .pre-commit-config.yaml file in the project repository. Here we define Git hooks for Black and Flake8.
repos:
- repo: https://github.com/python/black.git
rev: 19.10b0
hooks:
- id: black
language_version: python3
- repo: https://gitlab.com/pycqa/flake8.git
rev: 3.7.9
hooks:
- id: flake8
language_version: python3
When we install pre-commit, it creates a Git hook (a shell script) located in the hidden .git/hooks directory of a Git repository. These scripts automate your development processes. As we see, some Git hook scripts (files with the .sample extension) are already installed for our Git repository.
ls .git/hooks
To read the Git manual about githooks, run:
man githooks
Running pre-commit Hooks on Commit and on All Files
The pre-commit hook automatically runs code style and formatting checks when committing. As a result, the commit will not execute when the pre-commit check fails. We can also run pre-commit across all files in the repository.
pre-commit run --all-files
Sometimes there are issues we cannot fix at the moment, yet we still need to commit files to the repository. Use the --no-verify option to push your commit through without running the pre-commit hook.
git commit -am "commit message" --no-verify
Resolving โcommand not found: pre-commitโ
If pre-commit install returns command not found: pre-commit, the package is not on your PATH. Cause: pre-commit was installed into a different Python environment or user site directory. Fix it by reinstalling into the active environment and verifying the executable:
pip install --user pre-commit
python -m pre_commit --version
Conclusion: Git Pre-commit Workflow for PEP 8
A Git pre-commit hook enforces a simple, automated Python development cycle: Flake8 lints for PEP 8 and syntax errors, Black reformats files, and the commit is blocked until checks pass. We installed pre-commit for a Git repository and configured it to check code for Flake8 and Black issues.
Git Pre-commit FAQ
How do I install pre-commit in a Git repository?
Run pip install pre-commit to install the package, then pre-commit install inside the repository to register the Git hook in .git/hooks/pre-commit. The hook then runs automatically on every git commit.
How do I run pre-commit hooks on all files, not just staged ones?
Run pre-commit run --all-files. By default the hooks only check staged files; this command applies every configured hook (Black, Flake8) across the whole repository.
How do I commit when a pre-commit hook fails?
Use git commit -am "message" --no-verify. The --no-verify flag bypasses the pre-commit hook so the commit goes through, useful when a style issue cannot be fixed immediately. Use it sparingly.
What is the difference between Black and Flake8?
Black is an autoformatter that rewrites code to a consistent PEP 8 style, while Flake8 is a linter that reports PEP 8 violations and syntax errors without changing files. They are commonly used together in one .pre-commit-config.yaml.
References
- Black
- Black website
- realpython.com
- Flake8: Your Tool For Style Guide Enforcement
- โUsing Black with other toolsโ
- A framework for managing and maintaining multi-language pre-commit hooks
- How to Write Beautiful Python Code With PEP 8
Did you like this post? Please let me know if you have any comments or suggestions.
Posts about development tools and Python codingEnjoyed this? Get more like it.
Weekly notes on AI tools, Python, and what I'm actually building โ plus a free copy of Fantastic AI: The 2026 Toolkit.