Skip to content

Instantly share code, notes, and snippets.

@disouzam
Forked from MangaD/pre-commit.md
Created December 9, 2025 01:12
Show Gist options
  • Select an option

  • Save disouzam/4320660ebb7ebf3c884e923d7eef3df8 to your computer and use it in GitHub Desktop.

Select an option

Save disouzam/4320660ebb7ebf3c884e923d7eef3df8 to your computer and use it in GitHub Desktop.
The Comprehensive Guide to `pre-commit`

The Comprehensive Guide to pre-commit

Table of Contents

  1. Introduction: What is pre-commit?
  2. Why Use pre-commit?
  3. How pre-commit Works
  4. Installing and Setting Up pre-commit
  5. Configuring .pre-commit-config.yaml
  6. Built-in and Community Hooks
  7. How to Run and Use pre-commit
  8. Popular Use Cases
  9. Writing Custom Hooks
  10. Advanced Configuration and Features
  11. Integrating with CI/CD
  12. Best Practices
  13. Troubleshooting and Common Issues
  14. Alternatives and Related Tools
  15. Resources

1. Introduction: What is pre-commit?

pre-commit is an open-source framework for managing and maintaining multi-language pre-commit hooks. In software development, Git hooks are scripts that run automatically on specific Git events (e.g., commit, push). pre-commit makes it easy to install and run hooks for code quality, security, style, and more—before code gets committed.

It is language-agnostic and supports everything from Python, JavaScript, Go, and Shell scripts, to Rust, Ruby, and more.


2. Why Use pre-commit?

  • Automate Code Quality: Catch formatting errors, linting issues, and security flaws before they reach your repo.
  • Consistency Across Teams: Ensures everyone runs the same checks, reducing “works on my machine” problems.
  • Developer Productivity: Automates repetitive checks, freeing up dev time.
  • Multi-language Support: Works across codebases with multiple languages and ecosystems.
  • Easy CI/CD Integration: Hooks can be run manually or in CI to ensure consistency.

3. How pre-commit Works

  • You define a list of hooks (scripts) in a .pre-commit-config.yaml file.
  • pre-commit installs the required environments for each hook (virtualenvs, Node, etc.).
  • When you run git commit, pre-commit runs all the enabled hooks on the files you’re committing.
  • If a hook fails, the commit is blocked.

4. Installing and Setting Up pre-commit

Installation

  • Python users:

    pip install pre-commit
  • Homebrew (macOS/Linux):

    brew install pre-commit
  • Other: Install via conda, pipx, or download from GitHub.

Setting Up

  1. Add to your project:

    pre-commit sample-config > .pre-commit-config.yaml
  2. Install the Git hook scripts:

    pre-commit install

    This sets up .git/hooks/pre-commit to run pre-commit on every commit.

  3. Run on all files (initial run):

    pre-commit run --all-files

5. Configuring .pre-commit-config.yaml

This YAML file tells pre-commit which hooks to use and how to run them.

Example

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0  # Use the latest stable tag
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml

  - repo: https://github.com/psf/black
    rev: 24.3.0
    hooks:
      - id: black

Key Fields:

  • repo: URL or path to the repo with hooks
  • rev: Version tag or commit hash
  • hooks: List of hook definitions (id, args, files, etc.)

Hook Options

  • id: The hook’s unique name.
  • args: Custom arguments for the hook.
  • files: Regex for files to include.
  • exclude: Regex for files to exclude.
  • language_version: Set the language version (e.g., python3.11).

6. Built-in and Community Hooks

There’s a huge list of pre-commit hooks:


7. How to Run and Use pre-commit

  • On every commit: Automatically runs via the installed hook.

  • Manually on staged files:

    pre-commit run
  • On all files:

    pre-commit run --all-files
  • On a specific hook:

    pre-commit run black --all-files
  • Update all hooks:

    pre-commit autoupdate

8. Popular Use Cases

  • Enforce code style (formatters, linters)
  • Check for secrets (AWS keys, passwords)
  • Fix whitespace, newlines, EOF issues
  • Enforce commit message format
  • Check for large files or merge conflicts
  • Security vulnerability checks

9. Writing Custom Hooks

You can write your own hooks in any language.

Local Hook Example (in .pre-commit-config.yaml):

repos:
  - repo: local
    hooks:
      - id: my-linter
        name: My Custom Linter
        entry: ./scripts/my_linter.sh
        language: script
        files: \.py$

Local Python Hook Example

      - id: check-todo
        name: Check for TODOs
        entry: python scripts/check_todo.py
        language: python
        files: .*

Hook script must accept a list of filenames as arguments. Return 0 for pass, non-zero for fail.


10. Advanced Configuration and Features

  • Staged-only or all files: Use always_run, pass_filenames, and stages options.
  • Multiple stages: Use stages: [commit, push, manual].
  • Parallel execution: By default, hooks run in parallel.
  • Failing gracefully: Hooks can be set as required or optional.
  • Excluding files: Use the exclude regex for large/irrelevant files.
  • Languages: Hooks support many languages (python, node, golang, docker, system, etc.).
  • Hook ordering: Hooks run in the order they’re listed.

11. Integrating with CI/CD

  • Why: Ensures code quality checks run in CI, not just on developer machines.

  • How:

    • In your CI job, install pre-commit and run:

      pre-commit run --all-files --show-diff-on-failure
    • For some CIs (e.g., GitHub Actions), there are pre-built actions: pre-commit/action

  • Fail the build if hooks fail.


12. Best Practices

  • Pin hook versions: Always use specific rev values, never master/main.

  • Run pre-commit run --all-files after adding new hooks.

  • Add .pre-commit-config.yaml to source control.

  • Document setup in CONTRIBUTING.md.

  • Keep hooks fast—slow hooks slow down developer flow.

  • Autoupdate hooks regularly:

    pre-commit autoupdate
  • Review hook changes on update (some hooks change behavior across versions).


13. Troubleshooting and Common Issues

  • Hook not running? Did you run pre-commit install?

  • Hook fails but works manually? Check environment—pre-commit uses isolated environments for each hook.

  • Can’t find a hook or dependency? Sometimes you need to manually install system packages (e.g., libyaml-dev).

  • Files modified by hooks? By default, if a hook modifies files (e.g., a formatter), you must git add them and recommit.

  • Want to skip pre-commit just once?

    git commit --no-verify
  • Speed up repeated runs: Use pre-commit run --files ... or only staged files.

  • Cross-platform issues: Some hooks may have trouble on Windows—test in your team’s environments.


14. Alternatives and Related Tools

  • Husky (JavaScript-centric, popular in frontend projects)
  • lefthook (Go, cross-platform, fast)
  • Overcommit (Ruby)
  • git hooks (native, but more manual)

pre-commit is the most widely used and language-agnostic solution.


15. Resources


TL;DR / Executive Summary

  • pre-commit is a framework for managing and running Git hooks.
  • It is configured via .pre-commit-config.yaml and supports many languages.
  • You install it, configure hooks, and let it run checks/formatters automatically on commit.
  • It boosts code quality, developer experience, and consistency.

Have a specific use case or problem with pre-commit?

Let me know—I'm happy to go even deeper into any area, write advanced examples, or help troubleshoot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment