Tools

pre-commit: catch formatting issues and leaked secrets before you commit

TL;DR

pre-commit manages git hooks from one YAML file, installs each hook's tooling and runs only on changed files. Run pre-commit install once, autoupdate regularly, and always re-run run --all-files in CI.

Small mistakes like trailing whitespace, broken YAML, unsorted imports, or worse, an API key slipping into a commit, are usually caught only in CI or code review, after someone else's time has been spent. Git has a hook mechanism to run checks before each commit, but writing and sharing hooks across a team by hand is tedious. pre-commit is a framework for managing hooks: declare them in one YAML file, and it installs the right tool versions for each language and runs only on changed files.

GitHub page of pre-commit/pre-commit
GitHub page of pre-commit/pre-commit (screenshot, November 2026)

GitHub: https://github.com/pre-commit/pre-commit · about 16k stars · Python · MIT

Installation

pipx install pre-commit        # or: pip install pre-commit
uv tool install pre-commit     # if you use uv
brew install pre-commit        # macOS

Configuration

Create .pre-commit-config.yaml at the repo root. This example combines basic hooks, Ruff for Python and Gitleaks to block leaked secrets (versions as of writing; run pre-commit autoupdate for the latest):

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-added-large-files
        args: ["--maxkb=500"]
      - id: check-merge-conflict

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.17.3
    hooks:
      - id: ruff-check
        args: [--fix]
      - id: ruff-format

  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks

Then install the hooks into the repo:

pre-commit install                 # hooks into .git/hooks/pre-commit
pre-commit run --all-files         # first run across the whole repo

From now on, every git commit runs the hooks on staged files. Hooks that modify files (like ruff --fix or end-of-file-fixer) stop the commit; review the changes, git add again and commit.

Common commands

CommandEffect
pre-commit runRun hooks on staged files
pre-commit run ruff-check --all-filesRun one hook on the whole repo
pre-commit autoupdateBump every hook repo's rev to the latest
SKIP=gitleaks git commit ...Skip one specific hook for this commit
git commit --no-verifySkip all hooks (only when truly needed)
pre-commit install --hook-type pre-pushRun hooks on push instead of commit

Adding it to CI

Local hooks can be bypassed (--no-verify, or someone never installed them). So run them again in CI:

# A GitHub Actions step
- uses: actions/setup-python@v5
- run: pipx run pre-commit run --all-files --show-diff-on-failure

Another option is the pre-commit.ci service, which runs hooks automatically and can push fix-up commits to PRs.

Caveats

  • Slow hooks annoy developers into skipping them; keep heavy checks (full tests, deep scans) in CI and only fast ones in pre-commit.
  • Pin rev to tags, not branches, so everyone runs the same versions.
  • The first run downloads and builds an environment per hook, so it's slow; later runs use a cache.

How to apply it

  • Dev: Run pre-commit install right after cloning; formatting issues and secrets are caught before reaching reviewers.
  • Tech Lead: Start with a minimal set (whitespace, YAML, large files, gitleaks), add your main language's formatter/linter, and rerun in CI so nobody can bypass it.
  • PM: Code review focuses on logic rather than formatting, and the risk of leaked secrets, an incident that can be very costly, goes down.

Sources & references

  1. pre-commit/pre-commit — pre-commit (GitHub)
  2. pre-commit documentation — pre-commit