Hand-written hooks do not scale to dozens of checks in several languages. The pre-commit framework (github.com/pre-commit/pre-commit (https://github.com/pre-commit/pre-commit 15,598 ), MIT, version 4.6.2) reads .pre-commit-config.yaml, clones each hook repository at a pinned tag, builds an isolated environment for it (Python, Node.js 2,131 , Go, Rust, Docker 514 and more), and runs it on the staged files. Sam tries it on a scratch clone:
pipx install pre-commit
git clone -q ../server/booknest.git ../hooks-lab && cd ../hooks-lab
cat > .pre-commit-config.yaml <<'EOF'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: detect-private-key
- id: trailing-whitespace
EOF
pre-commit install
pre-commit run --all-files
cd ../booknest... installed package pre-commit 4.6.2, installed using Python 3.14.4 ... pre-commit installed at .git/hooks/pre-commit [INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks. ... check for added large files..............................................Passed detect private key.......................................................Passed trim trailing whitespace.................................................Passed
Environments are cached in ~/.cache/pre-commit, so only the first run is slow. pre-commit autoupdate moves each rev to the newest tag, and pre-commit run --all-files is the usual CI step. Hundreds of hooks are listed at pre-commit.com/hooks.html (https://pre-commit.com/hooks.html 187,261 ), from ESLint 39,810 to secret scanners such as gitleaks 29,524 . It refuses to install while core.hooksPath is set, so a repository picks one hook manager.