Les pubs vous déplaisent ? Aller Sans pub Auj.

Git Hooks Pré-commit, Pré-poussée et arrêt du mauvais code à la porte

Mis à jour le

Les hooks pre-commit, commit-msg et pre-push sont des scripts shell qui s'exécutent avant que git n'effectue un commit ou n'envoie une mise à jour. Voici comment les configurer pour détecter les échecs de vérification de code, des messages de commit incorrects et des secrets dévoilés — avec des exemples concrets que vous pouvez utiliser dès aujourd'hui.

Git Hooks : Pre-commit, Pre-push, et Arrêt des Codes Mauvais à la Porte 1
ANNONCE · Supprimer ?

Git inclut des hooks — des scripts en shell qui s'exécutent à des moments précis de votre flux de travail. La plupart des dépôts les ont enregistrés, inactifs dans .git/hooks/ comme .sample des fichiers. La plupart des développeurs les ignorent jusqu'à ce qu'un commit défectueux ou une clé API exposée les pousse à regretter qu'ils n'aient pas agi.

Cela couvre les trois hooks à configurer sur chaque projet : pre-commit, commit-msget pre-push. Chaque un intercepte une classe différente d'erreur. Chaque un est un script en shell que vous pouvez coller et utiliser dès aujourd'hui.

Où se trouvent les hooks

Chaque dépôt git possède un .git/hooks/ répertoire. Exécutez ls .git/hooks/ et vous verrez des fichiers d'exemple. Git ignore tout ce qui a le suffixe .sample . Pour activer un hook, supprimez le suffixe et faites-le exécutable :

cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

L'engagement est simple : sortir 0 et git continue. Sortir un code non nul et git s'arrête, affichant ce que vous avez écrit sur stderr.

pre-commit : votre hook à valeur maximale

pre-commit s'exécute après que vous ayez tapé git commit mais avant que l'objet du commit ne soit écrit. Il ne peut pas voir le message du commit — celui-ci n'est pas encore écrit. Ce qu'il pouvez fait, c'est inspecter les fichiers stagés et s'arrêter s'il y a quelque chose d'anormal.

Détail critique : utilisez git diff --cached --name-only pour obtenir uniquement les fichiers que vous avez effectivement stagés. L'intégration d'un linter sur tout le projet à chaque commit est lente et révèle des problèmes que vous n'avez pas introduits.

Exemple de linter (ESLint)

#!/bin/sh
# Lint only staged JS files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

echo "Running ESLint on staged files..."
echo "$STAGED_FILES" | xargs ./node_modules/.bin/eslint

if [ $? -ne 0 ]; then
  echo "ESLint failed. Fix errors before committing."
  exit 1
fi

exit 0

Le --diff-filter=ACM l'indicateur saute les fichiers supprimés — il n'y a pas de sens à essayer de vérifier un fichier que vous venez de supprimer.

Exemple de scan secret

Un scan brut de motif qui détecte les erreurs évidentes — des clés API exposées, des mots de passe dans des fichiers de configuration commités par erreur :

#!/bin/sh
# Block commits with obvious secrets
PATTERNS="(AWS_SECRET|api_key\s*=|password\s*=|PRIVATE KEY)"

if git diff --cached | grep -qiP "$PATTERNS"; then
  echo "Potential secret detected in staged changes. Aborting commit."
  exit 1
fi

exit 0

Pour les projets au-delà des exemples de jeu, associez-le à un scanner dédié. detect-secrets de Yelp fonctionne bien comme hook pre-commit — il maintient un fichier de référence afin que les chaînes déjà signalées ne bloquent chaque commit. trufflehog est mieux adapté pour le scan de l'historique après le fait ou pour s'exécuter dans CI.

commit-msg : imposer un format de message

Ce hook reçoit un argument : le chemin vers un fichier temporaire contenant votre message de commit provisoire. Le lisez, le validez, sortez 1 pour le rejeter. Le fichier est lisible — vous pouvez normaliser le message au lieu de le rejeter, bien que cela surprenne les gens la première fois.

Imposer Conventional Commits est l'usage le plus courant. Le rendement est des changelogs automatisés, une sortie lisible git log et des pipelines CI qui peuvent analyser les types de commit pour décider ce qu'ils doivent publier :

#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

# type(scope): description — scope is optional
PATTERN="^(feat|fix|chore|docs|style|refactor|test|perf|ci|build|revert)(\(.+\))?: .{1,72}"

if ! echo "$COMMIT_MSG" | grep -qP "$PATTERN"; then
  echo ""
  echo "Invalid commit message. Use Conventional Commits format:"
  echo "  type(scope): short description"
  echo ""
  echo "Valid types: feat, fix, chore, docs, style, refactor, test, perf, ci, build, revert"
  echo "Example:     feat(auth): add OAuth2 login flow"
  echo ""
  echo "Your message: $COMMIT_MSG"
  exit 1
fi

exit 0

Cela ne détectera pas un message valide mais sans sens comme fix: fix things. C'est un problème de culture, pas un problème de outil.

pre-push : la dernière porte avant l'origin

pre-push s'exécute après que git push soit invoqué mais avant que les données ne soient envoyées au serveur distant. Il reçoit le nom et l'URL du serveur distant via stdin. C'est là que doivent se trouver les tests — pas un linter (qui s'exécute en pre-commit), mais des tests réels qui vérifient le comportement.

#!/bin/sh
echo "Running tests before push..."

npm test

if [ $? -ne 0 ]; then
  echo "Tests failed. Push aborted."
  exit 1
fi

exit 0

Une vérité dure : si votre ensemble de tests dure plus de 60 à 90 secondes, les gens utiliseront --no-verify. Exécutez uniquement des tests unitaires rapides ici. Les tests d'intégration et les tests E2E appartiennent à CI où le lent est acceptable. Un hook trop lent pour être ignoré est pire qu'aucun hook.

Contourner les hooks — et quand c'est acceptable

git commit --no-verify
git push --no-verify

Les deux flags existent pour une raison. Un hook défectueux bloquant une correction d'urgence est ce qui fait que toute l'équipe rejette les hooks git comme concept. Utilisez --no-verify lorsque vous avez une raison valable : un hook qui se déclenche sur des fichiers non modifiés, ou une urgence où la correction est plus importante que la porte.

Si vous l'utilisez régulièrement, les hooks doivent être ajustés. Les coupables les plus fréquents : trop lent, échoue sur des fichiers non modifiés, ou des faux positifs de pattern que vous n'avez jamais nettoyés.

Partager les hooks avec votre équipe

.git/hooks/ est local à chaque clone — il est intentionnellement pas commis dans le dépôt. Deux approches pour que les hooks restent en place :

Option 1 : core.hooksPath

Stockez les hooks dans un répertoire commis (par exemple .githooks/), puis indiquez à git de l'utiliser :

git config core.hooksPath .githooks

Pour automatiser cela pour les nouveaux clones, ajoutez un prepare script à package.json — npm le lance automatiquement lors de npm install:

{
  "scripts": {
    "prepare": "git config core.hooksPath .githooks"
  }
}

Faites exécuter les scripts, les commettez, et tout le monde qui clone et exécute npm install obtient les hooks configurés automatiquement.

Option 2 : Husky

Husky est la solution standard pour les projets JavaScript/Node. Il gère la core.hooksPath connexion pour vous et donne à chaque hook un fichier dans .husky/:

npx husky init

Ajoutez ensuite les hooks comme des scripts en shell simples :

echo "npm test" > .husky/pre-push
chmod +x .husky/pre-push

Husky 9 (sorti début 2024) a abandonné la configuration JSON entièrement en faveur de scripts en shell simples. Plus simple que les versions v4/v8 pour les nouveaux déploiements, mais la migration de Husky 4 est un changement brisant que le guide officiel sous-estime — le format ancien .huskyrc ne fonctionne plus du tout. Si vous mettez à jour un dépôt existant, prévoyez du temps pour cela.

Les dépôts non JavaScript sont mieux servis par l' core.hooksPath approche. Il n'y a aucune raison de tirer une dépendance Node uniquement pour la gestion des hooks.

Vérifiez votre diff avant que le hook ne l'exécute

git diff --cached affiche les modifications stagées dans le terminal. Lorsque vous comparez deux versions d'un fichier de configuration ou que vous vérifiez ce qu'a réellement changé lors d'une refonte, une comparaison visuelle est plus rapide à scanner. IO Tools’ Text Diff vous permet de coller deux versions et de voir exactement ce qui a changé — utile lorsque vous souhaitez auditer ce qui entre dans un commit avant que les hooks ne s'exécutent.

Les hooks git sont l'un des rares outils d'automatisation qui vivent entièrement dans votre flux existant — sans compte CI, sans service supplémentaire, sans coût. Un hook pre-commit qui rejette une erreur de linting est aussi fiable que le script en shell que vous avez écrit. C'est une fonctionnalité : vous pouvez le lire, le déboguer et le modifier en une minute. Configurez les trois hooks ci-dessus et vous avez fermé la plus grande faille entre « cela fonctionne localement » et « cela fonctionne sur main. »

Envie d'une expérience sans pub ? Passez à la version sans pub

Installez nos extensions

Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide

Sur Extension Chrome Sur Extension de bord Sur Extension Firefox Sur Extension de l'opéra

Le Tableau de Bord Est Arrivé !

Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !

ANNONCE · Supprimer ?
ANNONCE · Supprimer ?
ANNONCE · Supprimer ?

Coin des nouvelles avec points forts techniques

Impliquez-vous

Aidez-nous à continuer à fournir des outils gratuits et précieux

Offre-moi un café
ANNONCE · Supprimer ?