guide/git-hooks.md

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 :

  1. 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
    
  2. 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-commit et commit-msg filtrent avant l'historique ; pre-push rejoue 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.

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.