Conventional commits e semantic versioning: la guida
Come scrivere messaggi di commit con una convenzione, cosa significano i numeri di versione tipo 2.4.1 e come le due cose si collegano tra loro.
Aprire lo storico di un progetto e trovare venti commit chiamati "fix", "update" e "modifiche" è un'esperienza comune e frustrante: la storia c'è, ma non dice niente. I conventional commits sono una convenzione per rendere quei messaggi leggibili — e si collegano direttamente a come si numerano le versioni. In questo articolo trovi entrambe le cose e il punto in cui si incastrano.
Il problema
Un messaggio di commit ha un solo scopo: spiegare perché una modifica è stata fatta.
Il cosa si vede dal codice. Il perché esiste solo nella testa di chi ha scritto — e sparisce in poche settimane. È il motivo per cui i messaggi generici sono uno spreco: occupano lo spazio dell'unica documentazione che non diventa mai obsoleta.
I conventional commits
È una convenzione che dà ai messaggi una struttura fissa, così che siano leggibili da una persona e interpretabili da uno strumento.
Il formato:
tipo(ambito): descrizione breve
corpo opzionale con più dettagli
footer opzionale
Esempi concreti:
feat(auth): aggiunge login con Google
fix(checkout): corregge il calcolo IVA per ordini esteri
docs: aggiorna le istruzioni di installazione
refactor(api): estrae la validazione in un modulo separato
I tipi principali
| Tipo | Quando |
|---|---|
feat | Nuova funzionalità |
fix | Correzione di un bug |
docs | Solo documentazione |
refactor | Riscrittura senza cambiare il comportamento |
test | Aggiunta o modifica di test |
chore | Manutenzione, dipendenze, configurazione |
perf | Miglioramento di prestazioni |
style | Formattazione, senza effetti sul codice |
I due che contano davvero sono feat e fix, per il motivo che vedremo tra poco. Gli altri sono utili ma non hanno conseguenze automatiche.
Le modifiche che rompono la compatibilità
Si segnalano con un punto esclamativo o con una nota nel footer:
feat(api)!: rimuove il parametro legacy dalla funzione di ricerca
BREAKING CHANGE: il parametro `oldFormat` non è più supportato.
Usare `format: 'legacy'` al suo posto.
È l'informazione più importante che un commit possa contenere, perché indica a chi usa il tuo codice che aggiornare richiederà delle modifiche.
Come scrivere la descrizione
Poche regole che rendono lo storico leggibile:
- All'imperativo presente: "aggiunge", non "aggiunto" o "aggiungo"
- Minuscola all'inizio, niente punto finale
- Sotto i 72 caratteri
- Descrivi il perché nel corpo, se non è ovvio dal titolo
Un test pratico: la descrizione dovrebbe completare la frase "Questo commit, se applicato, ...".
Il semantic versioning
Qui si collega la seconda metà.
Il semantic versioning è una convenzione per numerare le versioni in modo che il numero stesso dica cosa è cambiato.
MAJOR . MINOR . PATCH
2 . 4 . 1
| Parte | Si incrementa quando | Esempio |
|---|---|---|
| MAJOR | Rompi la compatibilità | 2.4.1 → 3.0.0 |
| MINOR | Aggiungi funzionalità compatibili | 2.4.1 → 2.5.0 |
| PATCH | Correggi bug senza rompere nulla | 2.4.1 → 2.4.2 |
Le regole pratiche da ricordare:
- Incrementando una parte, quelle a destra tornano a zero
- Lo zero iniziale (0.x.y) significa "instabile": tutto può cambiare, nessuna promessa di compatibilità
- La 1.0.0 è il momento in cui dichiari che l'interfaccia è stabile
Il valore del sistema è che chi usa il tuo codice sa cosa aspettarsi: una patch si aggiorna senza pensarci, una minor pure, una major richiede di leggere cosa è cambiato.
È anche il motivo per cui i gestori di dipendenze usano notazioni come ^2.4.1 — che significa "accetta tutti gli aggiornamenti fino alla prossima major".
Dove le due cose si incontrano
Ed è qui il vero motivo per cui vale la pena adottare i conventional commits.
La corrispondenza è diretta:
| Commit | Incrementa |
|---|---|
fix: | PATCH |
feat: | MINOR |
BREAKING CHANGE | MAJOR |
Se i commit seguono la convenzione, la versione successiva si calcola da sola. Esistono strumenti che, a ogni integrazione nel ramo principale, leggono i commit, determinano il nuovo numero di versione, generano il registro delle modifiche e pubblicano il rilascio — senza che nessuno decida nulla a mano.
Il collegamento naturale è con le automazioni che descrivo in cosa sono le GitHub Actions: il rilascio diventa una conseguenza dei commit, non un'attività separata.
Il registro delle modifiche generato automaticamente è l'altro beneficio concreto: raggruppato per tipo, con i riferimenti ai commit, senza che nessuno debba scriverlo.
Vale la pena adottarli?
Una valutazione onesta, perché non è sempre sì.
Sì, quasi certamente, se:
- Pubblichi una libreria o un pacchetto che altri usano
- Lavori in un team di più persone
- Vuoi generare rilasci e registro modifiche automaticamente
- Il progetto vivrà per anni
Probabilmente no se:
- È un progetto personale che non pubblicherai
- Sei da solo e il progetto è breve
- Il team non lo seguirà davvero
Il punto critico è l'ultimo. Una convenzione seguita a metà è peggio di nessuna convenzione: dà l'illusione di una struttura che non c'è, e gli strumenti automatici producono risultati sbagliati.
Se il team è d'accordo, un controllo automatico che verifica il formato dei messaggi lo rende semplice da mantenere.
Il minimo che vale sempre
Anche senza adottare la convenzione formale, due abitudini valgono per qualunque progetto:
Scrivi messaggi che spiegano il perché. "corregge il calcolo IVA sugli ordini extra-UE" batte "fix" in qualunque contesto, con o senza convenzioni.
Fai commit che contengono una cosa sola. Un commit che tocca tre argomenti diversi è illeggibile qualunque prefisso gli metti — ed è anche impossibile da annullare selettivamente.
Sono le stesse due qualità che rendono buona una pull request: uno scopo, e una spiegazione del motivo.
In sintesi
I conventional commits danno ai messaggi una struttura tipo(ambito): descrizione, dove i tipi che contano davvero sono feat, fix e la segnalazione delle rotture di compatibilità.
Il semantic versioning numera le versioni come MAJOR.MINOR.PATCH, dove il numero stesso dice se un aggiornamento è sicuro o richiede attenzione.
Le due cose si incastrano: con i commit strutturati, la versione successiva e il registro delle modifiche si generano da soli, e il rilascio diventa una conseguenza automatica del lavoro fatto.
Vale la pena adottarli su librerie pubbliche, progetti di squadra e cose destinate a durare. Su un progetto personale breve, sono complessità che non ripaga.
Ma le due abitudini che valgono sempre, con o senza convenzione, sono: spiega il perché, e fai commit che contengono una cosa sola.
Se i concetti base di Git non ti sono ancora familiari, il punto di partenza è cos'è il version control.