← Recipes

阅读中文版本

Add Pre-commit Hooks for Lint and Tests

Install the pre-commit framework, run lint and fast tests before every commit, and keep hooks reproducible across the team instead of relying on manual discipline.

~20 mingitqualityautomation

Task

Configure a repository-managed pre-commit hook that blocks commits when linting or fast tests fail.

When to use this

Broken formatting or failing tests repeatedly reach CI because local checks are manual. The team wants the same checks on every developer machine.

Prerequisites

  • Python 3.9+ or pipx for the pre-commit framework
  • A lint script and a fast test command in package.json
  • Git repository write access

Steps

1. Install the pre-commit framework once per machine, outside the project virtual environment.

pipx install pre-commit

Expected output: The pre-commit command is available on PATH.

2. Add a configuration that runs local project scripts. Use local hooks so the same package manager and versions as CI are used.

repos:
  - repo: local
    hooks:
      - id: lint
        name: lint
        entry: npm run lint
        language: system
        pass_filenames: false
      - id: unit-tests
        name: unit tests
        entry: npx vitest run --changed
        language: system
        pass_filenames: false

Expected output: A .pre-commit-config.yaml file exists at the repository root.

3. Install the Git hook and run all checks once to establish a baseline.

pre-commit install && pre-commit run --all-files

Expected output: Hooks are installed and the baseline run reports pass or fixable issues.

4. Verify the hook blocks a bad commit by introducing a lint error and attempting to commit.

git commit -m 'test hook'

Expected output: The commit is rejected and the lint failure is shown.

Troubleshooting

Problem

Hooks are slow

Solution

Run only changed files where supported, keep unit tests fast, and leave slower integration tests to CI.

Problem

Hooks differ across machines

Solution

Pin hook versions and use local hooks that call the project's locked package manager.

Limitations

  • Hooks can be bypassed with --no-verify; CI must remain the authoritative gate.
  • Pre-commit is client-side and cannot enforce checks on users who never install it.

Why repository-managed hooks

A hook living in one developer’s .git/hooks is invisible to everyone else. The pre-commit framework stores the configuration in the repository, pins versions, and installs the hook per clone.

repos:
  - repo: local
    hooks:
      - id: lint
        name: lint
        entry: npm run lint
        language: system
        pass_filenames: false
pipx install pre-commit
pre-commit install
pre-commit run --all-files

Verify

  • A commit with a lint error is rejected.
  • A clean commit succeeds without --no-verify.
  • A second developer clones the repo, runs pre-commit install, and gets the same checks.
  • CI still runs the same scripts; hooks are a fast local filter, not a replacement.

Scope

Keep hooks fast: formatting, lint, type-check, and unit tests. Put end-to-end, performance, and integration suites in CI. If a hook auto-fixes files, re-stage them and commit again.