Dopo averli introdotti durante l’esplorazione della git directory è giunto il momento di spendere qualche parola in più sugli hook in Git.
Gli hooks sono una funzionalità di Git che permette di automatizzare delle attività e rafforzare l’utilizzo delle linee guida durante l’esecuzione dei vari workflow.
Si tratta di script che Git esegue automaticamente al verificarsi di certi eventi (es. commit, push, merge).
Gli hooks si dividono in due categorie client side e server side. Quelli client side sono a loro volta suddivisi in un paio di sotto categorie:
- Committing-Workflow
- Email Workflow
In realtà non tutti gli hook client-side ricadono in queste due sub-categorie, molti non ne hanno una, ma rimangono comunque agganci estremamente utili.
Giusto per dare un’idea di cosa possiamo implementare con gli hook in Git, ecco qualche esempio:
- controllo del messaggio di commit
- applicazione degli standard prima di un push
- mandare una mail o un SMS dopo una commit
- formattazione, esecuzione dei test prima di una commit
- generazione di documentazione, aggiornamento delle dipendenze dopo un merge
- inviare il codice in produzione dopo un push
Nomenclatura degli hook
Tra poco vedremo una lunghissima lista di hook, anche se poi ci focalizzeremo solo su alcuni, quelli più comuni, ma sappiate che sulle nomenclature ci sono delle cose da tenere a mente:
- Gli eventi con radice
pre-
vengono eseguiti prima dell’evento - Gli eventi con radice
post-
vengono eseguito dopo l’evento - Gli eventi senza nessuna radice specifica vengono eseguiti durante l’evento
Il momento specifico di esecuzione varia da evento ad evento ed è consigliabile controllare sempre la documentazione.
Gli hook a disposizione
Gli hook a disposizione sono numerosissimi, 28 per la precisione:
- applypatch-msg
- pre-applypatch
- post-applypatch
- pre-commit
- pre-merge-commit
- prepare-commit-msg
- commit-msg
- post-commit
- pre-rebase
- post-checkout
- post-merge
- pre-push
- pre-receive
- update
- proc-receive
- post-receive
- post-update
- reference-transaction
- push-to-checkout
- pre-auto-gc
- post-rewrite
- sendemail-validate
- fsmonitor-watchman
- p4-changelist
- p4-prepare-changelist
- p4-post-changelist
- p4-pre-submit
- post-index-change
Nella documentazione di Git trovate una spiegazione per ognuno, qui di seguito darò una spiegazione dei più utilizzati:
pre-commit (Committing-Workflow)
Viene eseguito prima di una commit, prima ancora che venga scritto un messaggio di commit. Il suo utilizzo è vario, ma di base viene impiegato per: verificare di non aver dimenticato niente e/o per eseguire i test
prepare-commit-msg (Committing-Workflow)
Viene eseguito prima dell’avvio dell’editor dei messaggi di commit, ma dopo la creazione del messaggio di default e consente di modificarlo prima che l’autore lo veda.
Di per sé non è utilissimo se prendiamo in considerazione lo normali commit, ma è piuttosto utile quando il messaggio predefinito viene generato in automatico come nel caso di merge, squash o modifiche al messaggio originale (--amend).
commit-msg (Committing-Workflow)
Questo hook è utile per fare delle verifiche di conformità sul come è stato scritto il messaggio di commit.
post-commit (Committing-Workflow)
Eseguito dopo tutti quelli precedenti è utile se si vogliono implementare sistemi di notifica o cose simili.
applypatch-msg, pre-applypatch, post-applypatch (Email Workflow)
Tutti e tre i comandi vengono eseguiti dal comando git am
, un comando che non abbiamo mai visto durante le lezioni precedenti.
Il comando git am
accetta una o più patch di posta elettronica e le incorpora come commit nella branch locale.
Mentre una patch di posta elettronica è una rappresentazione testuale delle modifiche in una commit, formattata in modo che Git possa ricostruire la commit e applicarlo su un ramo in un altro repository.
applypatch-msg
è il primo hook ad essere eseguito ed esamina il messaggio di commit proposto. pre-applypatch
è il successivo ed è eseguito dopo l’applicazione della patch, ma prima della commit.
Infine, post-applypatch
viene eseguito dopo l’applicazione della commit.
Non vado troppo nel dettaglio perché non avendo mai affrontato il comando git am
verrebbe fuori solo un gran pastrocchio.
pre-rebase
Viene eseguito prima di un rebase e può interrompere il processo. Questo hook è usato per non dare la possibilità di fare il rebasing di una branch o, se ricordate le best practice di git rebase, per evitare che venga fatto il rebase di una commit che è stata già sincronizzata con la repo remota.
post-merge
Viene eseguito subito dopo un merge concluso con successo. Questo tipo di hook è utile per ripristinare dei file nel working tree che Git non tiene d’occhio.
pre-push
Viene eseguito durante il git push
dopo con le refs remote sono state aggiornate, ma prima di qualsiasi trasferimento. Si può utilizzare per validare delle ref in seguito all’aggiornamento.
pre-auto-gc
Viene eseguito prima dell’esecuzione del garbage collector e può essere usato per notificare l’avvio di questo processo o per fermarlo qualora non fosse un buon momento.
post-checkout
Viene eseguito subito dopo un git checkout
e può essere usato per impostare la working directory con specifiche impostazioni, le quali potrebbero anche essere semplicemente lo spostamento di grossi file che non vuoi tenere sotto traccia o generare della documentazione.
pre-receive
Il primo script ad essere eseguito server side quando si riceve un push da un client.
update
Simile a pre-receive, ma viene eseguito una volta per ogni branch che il client sta cercando di aggiornare.
post-receive
Viene eseguito alla conclusione del processo di ricezione dei dati e può essere usato per notificare l’utente dell’avvenuto push. Le applicazioni in questo caso sono molteplici:
- Inviare email
- Avviare un processo di continuous integration
- Parsificando il messaggio di commit si può anche aprire, chiudere o modificare un ticket
Quali linguaggi usare per scrivere gli hook in Git
Se ti stai chiedendo se puoi usare Python o Node, la risposta è sì. Gli script built-in sono in bash o PERL, ma in realtà è possibile usare un qualunque linguaggio di scripting, compresi Python e Node.
In ogni script basterà modificare la linea shebang #!/bin/sh nel linguaggio con la quale si vuole interpretare lo script:
#!/usr/bin/env python
#!/usr/bin/env node
Implementare un hook
Nella cartella .git/hook
possiamo rimuovere l’estensione .sample
a quello che vogliamo implementare. In caso di rinomina non bisognerà procedere con l’assegnazione dei privilegi di esecuzione, altrimenti nel caso creiate un nuovo file, perché volete mantenere il file sample dovrete, una volta creato fornirgli suddetti privilegi con il comando:
1$ chmod +x <path-hook>
Eseguendo il comando ls -l
dovreste vedere nella colonna dei permessi una x
alla fine -rwxr-xr-x
. Se così fosse allora il comando è andato a buon fine.
Un primo hook di test con Node
Cominciamo con un primo semplicissimo hook scritto in Node.
- Rinominiamo
pre-commit.sample
inpre-commit
e apriamolo in Visual Studio Code - Eliminiamo il contenuto e scriviamo quanto segue
1#!/usr/bin/env node
2console.log(“Ciao dal pre-commit in Node”);
- Facciamo una modifica nella nostra directory e salviamola con
git commit
- Subito prima del messaggio che solitamente visualizzavamo in seguito ad una commit vedremo il nostro messaggio
1Ciao dal pre-commit in Node
2[main 9a623cc] Aggiunto testo
3 1 file changed, 1 insertion(+)
- Complimenti hai creato il tuo primo hook in Node
Un secondo hook in Shell
Come prima lavoreremo nel pre-commit, se non hai fatto nessuna modifica dovrai seguire il punto 1 del precedente esperimento, altrimenti proseguire pure:
- Aprire
pre-commit
in VS Code - Eliminare il contenuto (o commentatelo)
- Scrivere quanto segue:
1#!/bin/sh
2
3echo "Stai per fare la commit di " $(git diff --cached --name-only --diff-filter=ACM)
4echo "in" $(git branch --show-current)
5
6while : ; do
7 read -p "Sicuro di voler procedere? [s/n] " RESPONSE < /dev/tty
8 case "${RESPONSE}" in
9 [Ss]* ) exit 0; break;;
10 [Nn]* ) exit 1;;
11 esac
12done
Lo script originale l’ho trovato su redhat.com h/t a loro per averlo scritto. Io mi sono limitato a tradurlo.
- Facciamo una modifica nella nostra directory e salviamola con
git commit
- Prima ancora di vedere l’esito della commit, vedremo un prompt che ci chiede se vogliamo proseguire, se accettiamo la commit prosegue e vedremo il solito output, altrimenti il processo verrà interrotto.
- Complimenti hai creato il tuo secondo hook.
Altri hook molto interessanti sono:
- Trovare i
console.log
prima di una commit che ci inviti a rimuoverli - Pubblicare un sito con gli hook
- Implementare hook in Git con Python
- Altri esempi di hook Git in Python
Conclusioni
Gli hook possono essere estremamente utili se usati correttamente. Passiamo quindi alla prossima e ultima lezione del corso di git per principianti.
Caricamento...
Diventiamo amici di penna? ✒️
Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.
Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!