Husky : messages de commit avec commitlint
commitlint vérifie que chaque message de commit respecte une convention. Associé au hook commit-msg de Husky, il refuse un message mal formé avant la création du commit. La convention la plus courante est Conventional Commits :
type(portée): description à l'impératif
corps facultatif
pied facultatif (BREAKING CHANGE: …, Closes #12)Installer
Section intitulée « Installer »npm install -D @commitlint/cli @commitlint/config-conventionalcommitlint.config.js :
export default { extends: ['@commitlint/config-conventional'],};(avec "type": "module" dans package.json ; sinon module.exports = { extends: [...] } ou le nom commitlint.config.cjs.)
Le hook commit-msg
Section intitulée « Le hook commit-msg »echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msgGit passe en paramètre le fichier contenant le message ($1) ; --no empêche npx de télécharger un paquet absent (et lance l’exécutable local). Tester :
git commit --allow-empty -m "n'importe quoi"⧗ input: n'importe quoi✖ subject may not be empty [subject-empty]✖ type may not be empty [type-empty]✖ found 2 problems, 0 warningsLe commit est refusé ; un message conforme passe :
git commit --allow-empty -m "chore: tester commitlint"Types de la configuration conventionnelle
Section intitulée « Types de la configuration conventionnelle »| Type | Usage |
|---|---|
feat |
Nouvelle fonctionnalité |
fix |
Correction de bogue |
docs |
Documentation |
style |
Mise en forme (sans effet sur le code) |
refactor |
Refactorisation |
perf |
Amélioration de performance |
test |
Ajout ou modification de tests |
build |
Système de construction, dépendances |
ci |
Intégration continue |
chore |
Tâches diverses |
revert |
Annulation d’un commit |
Exemples valides :
feat(projects): ajouter la grille de cartesfix(theme): corriger le flash au chargementdocs: mettre à jour l'introductionfeat(api)!: supprimer l'ancien point d'entrée
BREAKING CHANGE: la route /v1/clients n'existe plusUn ! après le type (ou une ligne BREAKING CHANGE: en pied) signale un changement cassant.
Règles : niveaux et valeurs
Section intitulée « Règles : niveaux et valeurs »export default { extends: ['@commitlint/config-conventional'], rules: { 'type-enum': [ 2, 'always', [ 'feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert', ], ], 'scope-enum': [ 2, 'always', ['theme', 'projects', 'docs', 'legal', 'deploy', 'config'], ], 'subject-case': [ 2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case'], ], 'subject-full-stop': [2, 'never', '.'], 'header-max-length': [2, 'always', 100], 'body-max-line-length': [1, 'always', 100], },};Chaque règle est [niveau, applicabilité, valeur] :
| Niveau | Effet |
|---|---|
0 |
Désactivée |
1 |
Avertissement (le commit passe) |
2 |
Erreur (le commit est refusé) |
Applicabilité : 'always' (la règle doit être respectée) ou 'never' (le contraire). La documentation de commitlint liste toutes les règles (type-case, scope-empty, body-leading-blank, footer-max-line-length…).
Exemple adapté à un projet en français
Section intitulée « Exemple adapté à un projet en français »Messages en français, description à l’impératif, en minuscules, sans point final :
export default { extends: ['@commitlint/config-conventional'], rules: { 'subject-case': [2, 'always', 'lower-case'], 'subject-full-stop': [2, 'never', '.'], 'scope-enum': [ 2, 'always', ['theme', 'projects', 'docs', 'legal', 'deploy', 'config'], ], 'header-max-length': [2, 'always', 100], },};La règle subject-case ne contrôle que la casse de la première lettre ; elle n’impose pas la langue.
Vérifier à la main
Section intitulée « Vérifier à la main »echo "feat(docs): ajouter la rubrique husky" | npx commitlintecho "mauvais message" | npx commitlintnpx commitlint --from HEAD~5 --to HEAD # les 5 derniers commitsnpx commitlint --last # le dernier commit--from et --to servent à vérifier tous les commits d’une branche en intégration continue (voir Intégration continue et équipes).
Messages générés par Git
Section intitulée « Messages générés par Git »commitlint ignore par défaut les messages de fusion (Merge branch …), d’annulation automatique (Revert "…") et de fixup!/squash! : ils ne déclenchent pas d’erreur. Pour modifier : l’option defaultIgnores et ignores de la configuration.
Générer un journal des modifications
Section intitulée « Générer un journal des modifications »Avec des messages normalisés, des outils produisent automatiquement un CHANGELOG.md et calculent le numéro de version (conventional-changelog, release-please, semantic-release). C’est l’un des principaux bénéfices d’une convention de messages appliquée par un hook.
Atomicité des commits
Section intitulée « Atomicité des commits »Une convention de messages va de pair avec des commits atomiques : un commit, un changement logique, qui compile et passe les tests. Utiliser git add -p pour séparer des modifications mêlées.
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
commitlint: command not found |
Dépendances non installées ; utiliser npx (hook) |
| Aucune erreur alors que le message est mauvais | Hook commit-msg absent ou non exécutable, --no-verify, core.hooksPath |
Please add rules to your commitlint.config.js |
Fichier de configuration absent ou introuvable (extension, type: module) |
Cannot find module '@commitlint/config-conventional' |
Paquet non installé |
subject may not be empty / type may not be empty |
Format type: description non respecté |
| Une portée valide est refusée | scope-enum ne la liste pas |
header must not be longer than 100 characters |
Raccourcir la première ligne, détailler dans le corps |
| Le message de fusion est refusé | Utiliser --no-verify pour cette fusion, ou ajouter un motif à ignores |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune.