Aller au contenu
BackFrontTips

Devenez accro aux crochets git

Apprenez à créer des hooks git pour automatiser vos tâches de développement et améliorer la qualité de vos projets.

Main tenant un autocollant avec le logo Git, photographié de près.
Photo by RealToughCandy.com / Pexels

Si vous travaillez avec Git, vous avez certainement remarqué le dossier .git à la racine de vos projets. Mais connaissiez-vous l'existence du sous-dossier hooks ?

$ ls -l .git/hooks
total 60
-rwxr-xr-x 1 amoevi amoevi  478 avril 23 11:20 applypatch-msg.sample
-rwxr-xr-x 1 amoevi amoevi  896 avril 23 11:20 commit-msg.sample
-rwxr-xr-x 1 amoevi amoevi 4655 avril 23 11:20 fsmonitor-watchman.sample
-rwxr-xr-x 1 amoevi amoevi  189 avril 23 11:20 post-update.sample
-rwxr-xr-x 1 amoevi amoevi  424 avril 23 11:20 pre-applypatch.sample
-rwxr-xr-x 1 amoevi amoevi 1643 avril 23 11:20 pre-commit.sample
-rwxr-xr-x 1 amoevi amoevi  416 avril 23 11:20 pre-merge-commit.sample
-rwxr-xr-x 1 amoevi amoevi 1492 avril 23 11:20 prepare-commit-msg.sample
-rwxr-xr-x 1 amoevi amoevi 1374 avril 23 11:20 pre-push.sample
-rwxr-xr-x 1 amoevi amoevi 4898 avril 23 11:20 pre-rebase.sample
-rwxr-xr-x 1 amoevi amoevi  544 avril 23 11:20 pre-receive.sample
-rwxr-xr-x 1 amoevi amoevi 2783 avril 23 11:20 push-to-checkout.sample
-rwxr-xr-x 1 amoevi amoevi 3650 avril 23 11:20 update.sample

Les hooks (ou crochets) sont des scripts personnalisables qui s'exécutent automatiquement à différentes étapes du cycle de vie Git. Nous allons découvrir leur potentiel et comment les utiliser afin d'automatiser certaines tâches pendant le développement.

La théorie

Un hook Git est donc un script qui s'exécute avant ou après des événements dans un dépôt Git. Il en existe deux types :

  • les hooks coté client : ils sont déclenchés localement par des opérations telles qu'un git commit ou un git merge.
  • les hooks coté serveur : ils sont exécutés par le serveur hébergeant le code et sont déclenchés lorsqu’il reçoit du code à la suite d’un git push.

Les crochets côté client sont locaux et ne sont pas copiés. Si vous comptez utiliser les scripts pour faire respecter les mêmes règles pour tous les développeurs travaillant sur un projet, il est recommandé d'utiliser des hooks serveur.

Par défaut, Git offre des exemples de crochets à la création d'un dépôt. Ils se trouvent dans le dossier .git/hooks, qu'on a vu en introduction.

Les hooks pre, tels que pre-commit ou pre-push, peuvent annuler l'action Git correspondante s'ils se terminent avec un code de sortie non nul. C'est donc avec ces crochets qu'il est intéressant de mettre en place des vérifications.

La pratique

Pour activer un hook, enlevez simplement le suffixe .sample, et il sera exécuté au moment de l'événement correspondant dans Git. Si vous partez de vos propres scripts, n'oubliez pas de vérifier les noms des fichiers correspondent aux actions Git et de contrôler les permissions d'exécution.

Les fichiers dans le dossier .git/hooks sont des scripts shell avec un peu de Perl. Mais vous pouvez implémenter les crochets avec votre langage favori, tant que les fichiers sont nommés correctement et exécutables.

Par exemple, on peut implémenter le hook pre-commit avec du Javascript.

#!/usr/bin/env node

const fs = require('fs');

if (!fs.existsSync('README.md')) {
  console.error('Erreur : README.md n\'existe pas.');
  process.exit(1);
}

process.exit(0);
.git/hooks/pre-commit

Le script pre-commit s'exécute à chaque fois que vous lancez git commit, avant que Git vous demande d'entrer un message de commit. Dans notre cas, le commit est annulé car il manque le README dans le dossier.

$ ls
src 	dist	lib
$ git commit
Erreur : README.md n'existe pas.

Autre vérification possible, on peut lancer une série de tests avant de réaliser un commit. Si les tests fonctionnent, tout va bien. Sinon, l'opération est annulée.

#!/bin/sh

echo "Exécution des tests Java..."

# Exécutez les tests avec Maven
mvn test

# Vérifiez le code de sortie de Maven
if [ $? -ne 0 ]; then
  echo "Les tests ont échoué. Annulation du commit."
  exit 1
fi

echo "Tous les tests ont réussi. Continuation du commit."
exit 0
.git/hooks/pre-commit

Contrairement au pre-commit, certains hooks reçoivent des paramètres qui sont utilisables lors de leur exécution. C'est le cas du commit-msg, qui reçoit le chemin du fichier contenant le message de commit. On peut ainsi utiliser cette valeur pour vérifier que le message de commit suit les règles du projet.

#!/usr/bin/env python3

import sys
import re

commit_msg_filepath = sys.argv[1]

with open(commit_msg_filepath, 'r') as file:
    commit_msg = file.read()

pattern = re.compile(r'^SFEIR-\d+: .+')

if not pattern.match(commit_msg):
    print("Le message de commit ne suit pas le format attendu (SFEIR-123: Description)")
    sys.exit(1)
.git/hooks/commit-msg

On peut observer l'effectivité du crochet avec les codes de sortie de la commande git commit.

$ git add sfeir.txt
$ git commit -m "Adding new file"
Le message de commit ne suit pas le format attendu (SFEIR-123: Description)
$ echo $? 
1
$ git commit -m "SFEIR-1: Adding new file"
[githooks 0ff1ce] SFEIR-1: Adding new file
$ echo $? 
0

Enfin, nous avons évoqué les hooks côté serveur et le fait que des hooks puissent se déclencher après l'évènement. Pour illustrer cela, on peut imaginer un crochet post-receive qui envoie un message sur un canal Slack dès que la branche main reçoit de nouveaux changements.

#!/bin/bash

# URL du webhook Slack
WEBHOOK_URL="URL_WEBHOOK_SLACK"

# Lire les informations du push
while read oldrev newrev refname; do
  # Vérifiez si le push est sur la branche main
  if [ "$refname" = "refs/heads/main" ]; then
    # Construire le message JSON
    JSON_TEXT="{\"text\":\"Un nouveau push a été effectué sur la branche main: $newrev\"}"

    # Envoyer la notification Slack
    curl -X POST --data-urlencode "payload=$JSON_TEXT" $WEBHOOK_URL
  fi
done
.git/hooks/post-receive

La documentation

Il existe d'autres hooks que nous n'avons pas abordés, comme le prepare-commit-msg qui permet de réécrire le message par défaut dans les commits ou le post-checkout qui est appelé après un git checkout ou git switch.

La commande man githooks décrit les crochets ainsi que leur utilisation. Il existe aussi une version web de cette page du manuel.

Sur ce même site, vous pouvez également trouver un exemple de politique git, qui implémente des hooks côté serveur et client en Ruby.

Dernier