W3docs

Git hooks

Impara i Git hooks: script eseguiti automaticamente nel ciclo di vita di Git per linting, test e validazione. Include un esempio pre-commit.

Cosa sono i Git hooks

I Git hooks sono script che Git esegue automaticamente quando si verificano determinati eventi — commit, merge, push e altro ancora. Consentono di collegare azioni personalizzate al ciclo di vita di Git: eseguire un linter prima di ogni commit, validare il formato del messaggio di commit, o bloccare un push se i test falliscono. Gli hooks sono il modo in cui i team applicano controlli di qualità localmente, prima che il codice difettoso lasci la macchina.

Questa pagina illustra dove risiedono gli hooks, la differenza tra hooks lato client e lato server, gli hooks più utili con esempi funzionanti, come un hook interrompe un'operazione, come bypassare un hook e come condividere gli hooks con un team.

Git hooks che si attivano nelle fasi del ciclo di vita di commit e push

Dove risiedono gli hooks

Ogni repository ha una directory .git/hooks contenente script di esempio con suffisso .sample. Per attivare un hook, aggiungere uno script eseguibile con il nome esatto dell'hook e senza estensione:

ls .git/hooks
# pre-commit.sample  commit-msg.sample  pre-push.sample ...

Rimuovere il suffisso .sample (o creare il file da zero) e renderlo eseguibile:

chmod +x .git/hooks/pre-commit

Un hook può essere scritto in qualsiasi linguaggio, purché il file sia eseguibile e inizi con una riga shebang appropriata (#!/bin/sh, #!/usr/bin/env python3, #!/usr/bin/env node, ecc.). Git si preoccupa solo che il file sia denominato esattamente come un hook noto, sia eseguibile e restituisca un codice di uscita.

Hooks lato client vs lato server

  • Gli hooks lato client vengono eseguiti sulla propria macchina intorno alle operazioni locali come commit e push. Sono ideali per linting e test.
  • Gli hooks lato server (come pre-receive e post-receive) vengono eseguiti sul repository remoto quando riceve un push — utili per applicare policy centralmente.

Gli hooks più comunemente usati sono lato client:

HookSi attivaUso tipico
pre-commitPrima che venga creato un commitLint e test dei file in staging; interrompe in caso di fallimento.
prepare-commit-msgPrima che si apra l'editor del messaggioInserisce un template o un numero di ticket.
commit-msgDopo che il messaggio è stato scrittoImpone una convenzione per i messaggi.
post-commitDopo il completamento di un commitInvia una notifica; nessun effetto sul commit.
pre-pushPrima che venga inviato un pushEsegue l'intera suite di test come controllo finale.

Come un hook interrompe un'operazione

L'intero meccanismo di controllo è il codice di uscita. Per un hook "pre-" (pre-commit, pre-push, commit-msg, …):

  • Uscita 0 → l'hook ha approvato l'operazione e Git continua.
  • Uscita diversa da zero → Git annulla l'operazione. Il commit non viene creato, o il push non viene inviato.

Gli hook "post-" (post-commit, post-merge, …) vengono eseguiti dopo che l'azione è già completata, quindi il loro codice di uscita viene ignorato — non possono annullare nulla. Usarli per le notifiche, non per la validazione.

Un esempio di pre-commit

Questo hook pre-commit esegue il linter del progetto e blocca il commit se rileva problemi. Poiché sh interrompe l'esecuzione al comando fallito grazie a set -e, non è necessario alcun controllo aggiuntivo di $?:

#!/bin/sh
set -e
echo "Running lint..."
npm run lint

Se npm run lint esce con un valore diverso da zero, set -e propaga quel codice e il commit viene interrotto. Se si preferisce un messaggio personalizzato, controllare il risultato esplicitamente:

#!/bin/sh
if ! npm run lint; then
  echo "Lint failed — commit aborted. Fix the issues and try again."
  exit 1
fi

Salvarlo come .git/hooks/pre-commit ed eseguire chmod +x .git/hooks/pre-commit.

Un esempio di commit-msg

L'hook commit-msg riceve un argomento: il percorso di un file temporaneo contenente il messaggio proposto. Leggere quel file, validarlo e uscire con un valore diverso da zero per rifiutarlo. Questo esempio impone un prefisso in stile Conventional Commits:

#!/bin/sh
# $1 is the path to the file containing the commit message
message=$(head -n1 "$1")
pattern='^(feat|fix|docs|style|refactor|test|chore): .+'

if ! echo "$message" | grep -Eq "$pattern"; then
  echo "Commit message must start with feat:, fix:, docs:, etc."
  exit 1
fi

Bypassare un hook

Un hook è una rete di sicurezza, non un muro. Quando si ha genuinamente bisogno di saltare gli hook pre-commit e commit-msg per un'operazione, usare --no-verify:

git commit --no-verify -m "WIP: skip checks"
git push --no-verify

Usare questa opzione con parsimonia — bypassare il linter è il modo in cui il codice difettoso si insinua nella cronologia.

Condividere gli hooks con un team

Poiché .git/hooks non viene committato, gli hooks non vengono trasferiti con un clone. I team risolvono questo problema memorizzando gli hooks in una directory tracciata e puntando Git ad essa:

git config core.hooksPath .githooks

Ora Git cerca nella directory tracciata .githooks/ invece di .git/hooks. Committare gli script lì, renderli eseguibili, e ogni membro del team li riceverà dopo aver eseguito lo stesso comando git config (o dopo che uno script di configurazione lo fa per loro). Consultare Git config per ulteriori informazioni sulla memorizzazione delle impostazioni per repository.

Strumenti come Husky automatizzano esattamente questo per i progetti JavaScript, configurando hooks condivisi durante l'installazione. Per le policy che non si può permettere a nessuno di bypassare con --no-verify, applicarle con hooks lato server o con la protezione dei branch della propria piattaforma di hosting, poiché gli hooks lato client risiedono sempre sulla macchina dello sviluppatore.

Argomenti correlati

  • git commit — il comando intorno a cui si avvolgono gli hooks pre-commit e commit-msg.
  • Firma dei commit — verifica dell'autorship, spesso abbinata agli hooks.
  • Git config — dove vengono memorizzati core.hooksPath e altre impostazioni.
  • Git alias — scorciatoie per i comandi eseguiti dagli hooks.

Pratica

Pratica
Quali affermazioni sui Git hooks sono corrette?
Quali affermazioni sui Git hooks sono corrette?
Was this page helpful?