Elena' s AI Blog

Linters and Git Pre-commit

11 Sep 2022 (updated: 01 Jun 2026) / 8 minutes to read

Elena Daehnhardt


Precise version control workflow illustration


TL;DR:
  • Setting up Git pre-commit hooks with linters: automatically checking Python code style (PEP 8) before committing files to maintain coding standards and code quality.

Previous: Part 19 โ€” GitHub Codespaces

Next: Part 21 โ€” The SSH host key mystery

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:

  1. ensure correct code formatting and style;
  2. minimise syntax errors;
  3. help in code reviews;
  4. 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
Git hook files

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

  1. Black
  2. Black website
  3. realpython.com
  4. Flake8: Your Tool For Style Guide Enforcement
  5. โ€œUsing Black with other toolsโ€
  6. A framework for managing and maintaining multi-language pre-commit hooks
  7. 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 coding

desktop bg dark

About Elena

Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.

Citation
Elena Daehnhardt. (2022) 'Linters and Git Pre-commit', daehnhardt.com, 11 September 2022. Available at: https://daehnhardt.com/blog/2022/09/11/edaehn-git-pre-commit/
All Posts