# pre-commit: Git Hook Framework for Python

pre-commit is a framework for managing reusable Git hooks. A project declares hooks in `.pre-commit-config.yaml`; pre-commit installs each hook's runtime environment, runs hooks at selected Git stages, and blocks the Git operation when a hook fails or modifies files.

In Python projects, pre-commit commonly runs [Ruff](https://pydevtools.com/handbook/reference/ruff.md), [mypy](https://pydevtools.com/handbook/reference/mypy.md), [ty](https://pydevtools.com/handbook/reference/ty.md), whitespace checks, YAML checks, and repository-local scripts. For setup steps, see [How to set up pre-commit hooks for a Python project](https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project.md).

## Key Features

* Git hook installation: writes hook scripts for `pre-commit`, `pre-push`, `commit-msg`, and other supported Git hook stages.
* Shared configuration: reads `.pre-commit-config.yaml` from the repository root.
* Pinned hook revisions: clones remote hook repositories at the configured `rev:` so teams run the same hook code.
* Isolated hook environments: creates language-specific environments for Python, Node, Ruby, Go, Rust, Docker, and other hook backends.
* File filtering: runs hooks only on matching files by default, with options for all files, explicit files, or files changed between refs.
* Manual runs: supports `pre-commit run`, `pre-commit run --all-files`, and `pre-commit run <hook-id>`.
* Hook updates: updates configured hook repository revisions with `pre-commit autoupdate`.

## Configuration

The main configuration file is `.pre-commit-config.yaml`. Each entry names a hook repository, a pinned revision, and one or more hook IDs:

```yaml {filename=".pre-commit-config.yaml"}
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
```

Hook entries can override file patterns, arguments, language versions, stages, and additional dependencies. Hook authors publish metadata in `.pre-commit-hooks.yaml`, which tells pre-commit the hook ID, name, entry point, language backend, and file matching rules.

## Hook Stages

Despite its name, pre-commit is not limited to the `pre-commit` Git stage. It supports client-side Git hooks such as `pre-push`, `commit-msg`, `prepare-commit-msg`, `post-checkout`, `post-commit`, `post-merge`, `post-rewrite`, `pre-rebase`, and `pre-merge-commit`, plus the special `manual` stage for hooks run on demand with `pre-commit run --hook-stage manual`.

Projects can install more than one stage with repeated `--hook-type` flags or by setting `default_install_hook_types` in `.pre-commit-config.yaml`.

## Python Project Fit

pre-commit fits projects that want the same checks to run before every commit without asking each contributor to remember separate commands. It is especially common for formatting and linting gates, because those tools can fix files before review.

pre-commit does not replace [pytest](https://pydevtools.com/handbook/reference/pytest.md), a type checker, or CI. It runs configured tools at a Git boundary. CI still needs to run merge-blocking checks because contributors can skip local hooks with `git commit --no-verify` or by not installing hooks.

## pre-commit and prek

[prek](https://pydevtools.com/handbook/reference/prek.md) is a compatible reimplementation of pre-commit. It reads the same `.pre-commit-config.yaml` format and is designed as a drop-in replacement for the original CLI.

Use pre-commit when the project wants the original implementation, the broadest compatibility with documented pre-commit behavior, or a conservative default already known by contributors. Use prek when the project wants faster hook installation and execution while keeping the same configuration file.

## Pros

* Standard hook format used across many Python repositories
* Reusable hook repositories instead of copied local shell scripts
* Per-hook isolated environments for language-specific tools
* Pinned hook revisions for consistent local and CI behavior
* Works with Python and non-Python tooling in the same repository
* CI-friendly `run --all-files` workflow

## Cons

* Hooks must be installed locally before `git commit` runs them
* Contributors can bypass hooks with `--no-verify`
* First runs can be slower while hook repositories and environments install
* Python-based implementation is slower than compatible tools such as prek
* Hook isolation can surprise tools that need project dependencies unless the hook config supplies them

## Learn More

* [How to set up pre-commit hooks for a Python project](https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project.md)
* [prek reference](https://pydevtools.com/handbook/reference/prek.md)
* [How to stop AI agents from bypassing pre-commit hooks](https://pydevtools.com/handbook/how-to/how-to-stop-ai-agents-from-bypassing-pre-commit-hooks.md)
