pre-commit
Un framework qui lance automatiquement des vérifications sur tes fichiers avant chaque commit Git. Tu configures une fois ce que tu veux vérifier (linter, formateur, tests, secrets…), et pre-commit s'assure que rien de cassé ne passe dans l'historique du projet.
À quoi ça sert
En théorie, on devrait toujours lancer Ruff, pytest, ou un check de formatage avant de pousser du code. En pratique, on oublie. La CI/CD finit par attraper le problème, mais on a déjà perdu 5 minutes à attendre les jobs GitHub et tout le monde voit passer le « fix lint » dans l'historique.
Pre-commit règle ça en plaçant un hook Git qui
intercepte la commande git commit : il lance tes
vérifications, et si l'une échoue, le commit est bloqué.
Tu corriges, tu re-commit, ça passe. La CI ne voit jamais de problème
de format.
- Lancer Ruff / Black / isort sur les fichiers Python modifiés.
- Vérifier le YAML, le TOML, le JSON de config (pas de fichier mal formé qui casse le build).
- Bloquer les secrets committés par erreur (clés API,
mots de passe…) avec
detect-secrets. - Lancer pytest sur les tests rapides avant un commit important.
- Auto-corriger ce qui est corrigible : trailing whitespace, fins de ligne, ordre des imports…
Un hook Git est un script que Git exécute à un
moment précis : avant un commit (pre-commit), avant un
push (pre-push), etc. Ils existent depuis toujours dans
Git, mais sont relous à gérer à la main (un script par hook, par
machine, par projet…). L'outil pre-commit (l'outil, à ne
pas confondre avec le hook du même nom) industrialise tout ça :
une config YAML versionnée dans le repo, un partage automatique
entre l'équipe.
Un exemple d'usage
Tu actives Ruff (lint + format) sur ton projet. Tu modifies un fichier avec un import inutilisé et des espaces de fin de ligne, tu commits :
git commit -m "feat: nouvelle route"
ruff (lint).............................................................Failed
- hook id: ruff
- exit code: 1
src/api.py:3:1: F401 [*] `os` imported but unused
Found 1 error.
trim trailing whitespace................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing src/api.py
Le commit a été bloqué. Ruff a signalé l'import inutile,
le hook trailing-whitespace a même corrigé le fichier tout
seul. Tu corriges l'import, tu re-stage les changements, tu re-commit —
cette fois tous les hooks passent et le commit est créé.
How-to : installer et utiliser pre-commit
-
Installer l'outil
pre-commit est un outil en ligne de commande, indépendant de ton projet (comme Ruff ou UV). On l'installe globalement avec
uv tool:bashuv tool install pre-commit # Vérifier pre-commit --versionTu peux aussi l'ajouter comme dépendance dev de ton projet (
uv add --dev pre-commit) si tu préfères qu'il soit installé automatiquement paruv sync. -
Créer le fichier de config
Toute la configuration tient dans un fichier
.pre-commit-config.yamlà la racine du repo. On y liste les repos de hooks à utiliser et leurs versions :yaml (.pre-commit-config.yaml)repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.8.0 hooks: - id: ruff args: [--fix] - id: ruff-formatChaque
repoest un dépôt Git contenant un ou plusieurs hooks.revfige une version pour la reproductibilité (toute l'équipe utilise exactement la même). -
Installer les hooks dans ton repo
Une seule fois par clone du repo, après avoir créé le YAML :
bashpre-commit installÇa crée le fichier
.git/hooks/pre-commitqui appelle l'outil. À partir de là, chaquegit commitdans ce repo va lancer les hooks définis dans ton YAML.Et pour les nouveaux clones ?Le
.pre-commit-config.yamlest versionné dans Git, mais le hook.git/hooks/pre-commit, non (Git n'inclut jamais son propre dossier). Chaque personne qui clone doit lancerpre-commit installune fois. C'est une bonne ligne à mettre dans le README. -
Lancer manuellement (sans commiter)
Utile la première fois ou après avoir ajouté un hook, pour corriger d'un coup tout le code existant :
bash# Sur les fichiers modifiés (= staged), comme pendant un commit pre-commit run # Sur TOUT le repo pre-commit run --all-files # Un seul hook pre-commit run ruff --all-files -
Mettre à jour les versions des hooks
Les hooks listés dans le YAML sont figés à une version. Pour les passer aux dernières versions stables :
bashpre-commit autoupdateÇa réécrit les
rev:dans ton YAML. Tu commits le fichier modifié et toute l'équipe récupère les nouvelles versions au prochain pull. -
Quelques hooks utiles
Le dépôt
pre-commit-hooksofficiel contient une collection de checks génériques très pratiques :trailing-whitespace— enlève les espaces de fin de ligne.end-of-file-fixer— assure une seule ligne vide à la fin du fichier.check-yaml/check-toml/check-json— valide la syntaxe.check-added-large-files— bloque les fichiers trop gros (modèles, datasets accidentels).check-merge-conflict— détecte les<<<<oubliés.detect-private-key— empêche de commiter une clé SSH par erreur.
Pour Python, les incontournables :
ruff+ruff-format— lint et formatage (cf. Ruff).mypy— vérification statique des types.detect-secrets— bloque les mots de passe et tokens.
-
Contourner ponctuellement (à utiliser avec parcimonie)
Si tu dois absolument commiter sans déclencher les hooks (urgence, WIP local) :
bashgit commit --no-verify -m "WIP"Pourquoi pas systématiquement ?--no-verifycontourne tous les hooks Git, y compris ceux qui vérifient les messages de commit ou la signature. Si tu te retrouves à l'utiliser souvent, c'est soit que tes hooks sont trop lents (réfléchir à ce qu'on lance pré-commit vs pré-push), soit qu'ils râlent à tort (ajuster la config). -
L'intégrer aussi en CI
Même avec pre-commit installé localement, on relance les hooks dans la CI : ça protège contre les
git commit --no-verifyet les contributeurs qui n'ont paspre-commit installé. Étape type dans un workflow GitHub Actions :yaml (.github/workflows/ci.yml)- uses: actions/setup-python@v5 with: python-version: "3.12" - uses: pre-commit/action@v3.0.1
Aide-mémoire
uv tool install pre-commit
pre-commit install # active les hooks Git
pre-commit run --all-files # lance sur tout
pre-commit run <hook-id> # un seul hook
pre-commit autoupdate # bumper les versions
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
pre-commit et le reste de l'écosystème
- Ruff — c'est le hook que tu installes en premier. Lint + formatage Python sur les fichiers modifiés, en quelques millisecondes.
-
pytest — on peut lancer
les tests rapides en pre-commit, mais en général c'est trop lent
pour bloquer chaque commit. Préfère un hook
pre-pushou la CI/CD. - CI/CD — pre-commit local et CI sont complémentaires : le local évite les allers-retours, la CI est le filet de sécurité officiel. On y rejoue les mêmes hooks pour cohérence.
-
GitHub /
GitLab — les actions
officielles
pre-commit/actionfacilitent l'intégration en CI. Sur GitLab CI, on appelle directementpre-commit run --all-filesdans un job. -
docstring — on peut
ajouter un hook
pydocstylepour vérifier la présence et le format des docstrings.
Un commit ne devrait pas attendre plus de 2-3 secondes. Si tes hooks dépassent ce seuil, tu vas finir par les contourner. Garde en pre-commit les checks rapides (lint, format), et bascule les checks lents (tests d'intégration, build Docker) en pre-push ou en CI.
Pour aller plus loin
- Site officiel : pre-commit.com
- Liste des hooks « génériques » : github.com/pre-commit/pre-commit-hooks
- Hooks Ruff officiels : github.com/astral-sh/ruff-pre-commit
- Action GitHub officielle : github.com/pre-commit/action