Automatiser des contrĂ´les par git hooks
Ce guide part du principe que vous connaissez déjà Git et que vous voulez imposer des contrôles automatiques sur vos commits et vos pushs : linting, format de message, absence de secrets, rejeu local de la CI. Vous obtiendrez à la fin une configuration versionnée et partageable dans l'équipe.
Le mécanisme en une phrase
Un hook est un script exécutable rangé dans .git/hooks/. Git le lance à un moment précis du cycle (commit, push, merge…). Code de sortie 0 = l'action continue ; code non nul = l'action est bloquée. C'est ce blocage qui fait de vous un garde-fou.
Écrire un hook
Un hook peut être écrit dans n'importe quel langage disponible sur la machine, tant que le fichier commence par un shebang valide :
- Bash :
#!/bin/bash - PHP :
#!/usr/bin/php - Python :
#!/usr/bin/python
Rendez le fichier exécutable :
chmod +x .git/hooks/pre-commit
Choisir le bon hook selon le contrôle visé
| Hook | Se déclenche | À utiliser pour |
|---|---|---|
pre-commit |
avant la création du commit | linting, tests unitaires rapides, détection de secrets |
prepare-commit-msg |
avant l'ouverture de l'éditeur de message | pré-remplir le message (ex. numéro de ticket) |
commit-msg |
après la rédaction du message | valider le format (préfixes feat:, fix:, docs:, Conventional Commits) |
post-merge |
après un pull/merge réussi |
relancer l'installation des dépendances si le lockfile a changé, vider un cache |
pre-push |
avant l'envoi vers le distant | rejouer en local les vérifs de la CI (échec rapide avant de pousser) |
Exemple : bloquer un commit qui contient un secret
Dans pre-commit, faites échouer le hook (sortie non nulle) dès qu'un motif suspect apparaît dans les fichiers indexés :
#!/bin/bash if git diff --cached | grep -E '(api[_-]?key|password|secret|token)\s*=' ; then echo "Secret potentiel détecté — commit bloqué." exit 1 fi exit 0
Exemple : valider le format du message
Dans commit-msg, le premier argument est le fichier contenant le message :
#!/bin/bash if ! head -1 "$1" | grep -qE '^(feat|fix|docs|chore|refactor|test)(\(.+\))?: '; then echo "Message non conforme aux Conventional Commits." exit 1 fi
Local ou serveur ?
| Type | Emplacement | RĂ´le |
|---|---|---|
| Locaux | machine du développeur | valider avant commit/push, formater |
| Serveur | plateforme Git ou serveur distant | rejeter un push non conforme, déclencher un déploiement |
Les hooks serveur (ex. pre-receive) donnent la garantie forte : ils s'exécutent côté distant et personne ne peut les contourner. Les hooks locaux, eux, dépendent de la bonne volonté de chaque poste — utiles pour le confort et l'échec rapide, mais ne les considérez pas comme un contrôle de sécurité opposable.
Versionner et partager les hooks (l'étape qui manque souvent)
Piège classique : .git/hooks/ n'est pas versionné et n'est jamais poussé. Un hook posé chez vous n'existe pas chez vos collègues. Deux stratégies pour corriger ça :
-
Rediriger le dossier des hooks (Git 2.9+) vers un dossier versionné du dépôt. C'est le plus propre : une seule commande, valable pour toute l'équipe.
git config core.hooksPath scripts/hooks
-
Lien symbolique depuis un dossier versionné vers
.git/hooks/, hook par hook :ln -s ../../scripts/hooks/pre-commit .git/hooks/pre-commit
Placez vos scripts dans un dossier versionné (par convention scripts/hooks/), documentez la commande d'activation dans le README, et faites-la exécuter une fois à chaque nouvel arrivant.
Récapitulatif
- Le hook bloque quand il sort en code non nul : c'est votre levier.
pre-commitetcommit-msgfiltrent avant l'historique ;pre-pushrejoue la CI en local ; les hooks serveur seuls sont opposables.- Ce qui n'est pas dans
core.hooksPath(ou lié symboliquement) ne s'applique à personne d'autre que vous : versionnez et documentez l'activation.