Introduzione
Git è lo standard de facto per il version control nel 2026, usato dal 94% dei developer professionisti secondo l'ultima Stack Overflow Survey. Eppure la maggior parte degli sviluppatori usa solo una manciata di comandi — clone, commit, push — perdendosi strumenti potenti che potrebbero fargli risparmiare ore ogni settimana.
Questa guida copre Git da due angolazioni: i comandi essenziali per chi inizia, e le strategie di workflow per chi lavora in team e vuole evitare disastri in produzione.
Non importa se stai facendo i primi passi o se usi Git da anni ma senti di non sfruttarlo al massimo: alla fine di questo articolo avrai una comprensione completa di come funziona Git sotto il cofano e come usarlo in modo efficace nei progetti reali.
Cos'è Git e perché è diverso dagli altri sistemi di versioning
Git è un sistema di controllo versione distribuito (DVCS) creato da Linus Torvalds nel 2005 per gestire lo sviluppo del kernel Linux. A differenza di sistemi centralizzati come SVN, ogni sviluppatore ha una copia completa della storia del progetto sul proprio computer.
Questa caratteristica fondamentale porta tre vantaggi pratici:
- Lavoro offline completo — puoi fare commit, creare branch, consultare la storia senza connessione internet
- Velocità estrema — le operazioni sono locali, quindi istantanee (un merge di 1000 file richiede millisecondi)
- Backup naturale — ogni clone è un backup completo del repository
Git non salva le differenze tra versioni — salva snapshot completi del progetto. Ogni commit è una foto istantanea dell'intero stato dei file.
Questa architettura rende Git più complesso da imparare rispetto a sistemi più semplici, ma infinitamente più potente una volta compreso il modello mentale.
I tre stati di Git: il concetto chiave da capire
Prima di imparare i comandi, devi capire come Git organizza i file. Ogni file nel tuo progetto può trovarsi in uno di tre stati:
1. Working Directory (modificato)
La cartella del progetto sul tuo computer. Qui modifichi i file normalmente. Git rileva le modifiche ma non le traccia ancora.
2. Staging Area (preparato)
L'area intermedia dove selezioni quali modifiche includere nel prossimo commit. Questo è il concetto che confonde di più chi viene da altri sistemi di versioning, ma è anche la killer feature di Git.
Con git add sposti i file dalla Working Directory alla Staging Area. Puoi fare modifiche a 10 file ma mettere in staging solo 3, creando commit granulari e ben organizzati.
3. Repository (committato)
La storia permanente del progetto. Quando fai git commit, Git crea uno snapshot di tutto ciò che è in staging e lo salva nel repository locale.
Esempio pratico del flusso:
# 1. Modifichi index.html e style.css
# Stato: entrambi in Working Directory
# 2. Prepari solo index.html per il commit
git add index.html
# Stato: index.html in Staging, style.css in Working Directory
# 3. Salvi lo snapshot
git commit -m "Add hero section to homepage"
# Stato: index.html committato, style.css ancora modificato
Questo meccanismo ti permette di organizzare modifiche complesse in commit logici e atomici, invece di avere un singolo mega-commit con tutto mescolato.
I 15 comandi Git essenziali che usi ogni giorno
Inizializzazione e clonazione
git init — Trasforma una cartella normale in un repository Git
mkdir mio-progetto
cd mio-progetto
git init
# Crea la cartella nascosta .git con tutta la struttura
git clone <url> — Scarica una copia completa di un repository remoto
git clone https://github.com/username/repo.git
# Crea la cartella 'repo' con tutto lo storico
Lavorare con i file
git status — Mostra lo stato attuale del repository
git status
# Output: file modificati, in staging, non tracciati
Usalo ossessivamente. È il comando che usi prima e dopo ogni altra operazione per capire dove sei.
git add <file> — Sposta file nella Staging Area
git add index.html # Aggiunge un singolo file
git add . # Aggiunge tutto nella cartella corrente
git add *.js # Aggiunge tutti i file .js
git commit -m "messaggio" — Salva lo snapshot con un messaggio descrittivo
git commit -m "Fix login validation bug"
Best practice per i messaggi di commit:
- Prima riga: massimo 50 caratteri, imperativo presente ("Add feature" non "Added feature")
- Riga vuota
- Descrizione dettagliata se necessario
Consultare la storia
git log — Mostra la cronologia dei commit
git log # Storia completa
git log --oneline # Versione compatta (un commit per riga)
git log --graph --all # Vista grafica con tutti i branch
git diff — Mostra le differenze tra versioni
git diff # Modifiche non ancora in staging
git diff --staged # Modifiche in staging
git diff HEAD~1 # Differenze rispetto al commit precedente
Sincronizzazione con il remoto
git remote add origin <url> — Collega il repository locale a uno remoto
git remote add origin https://github.com/username/repo.git
git remote -v # Verifica i remote configurati
git push — Invia i commit locali al repository remoto
git push origin main # Invia il branch main a origin
git push -u origin main # Imposta main come branch di tracking
git pull — Scarica e integra le modifiche dal remoto
git pull origin main
# Equivale a: git fetch + git merge
git fetch — Scarica le modifiche senza integrarle
git fetch origin
# Aggiorna i riferimenti ai branch remoti ma non tocca il tuo codice
Branching: lavorare su più versioni in parallelo
Il branching è dove Git mostra la sua vera potenza. Un branch è semplicemente un puntatore mobile a un commit — crearlo e cancellarlo è istantaneo e non duplica alcun file.
Comandi base per i branch
git branch — Gestisce i branch
git branch # Lista i branch locali
git branch feature-login # Crea un nuovo branch
git branch -d feature-login # Cancella un branch (solo se mergiato)
git branch -D feature-login # Forza la cancellazione
git checkout / git switch — Cambia branch
# Sintassi classica
git checkout feature-login
# Sintassi moderna (Git 2.23+)
git switch feature-login
git switch -c nuova-feature # Crea e passa al nuovo branch
git merge — Unisce un branch nel branch corrente
git switch main
git merge feature-login
# Integra le modifiche di feature-login in main
Strategia Git Flow: il workflow standard per i team
Git Flow è una convenzione di branching che definisce ruoli precisi per ogni tipo di branch. Funziona così:
| Branch | Scopo | Lifetime |
|---|---|---|
main |
Codice in produzione, sempre stabile | Permanente |
develop |
Branch di integrazione per lo sviluppo | Permanente |
feature/* |
Sviluppo di nuove funzionalità | Temporaneo |
release/* |
Preparazione release (bug fix finali) | Temporaneo |
hotfix/* |
Fix urgenti per produzione | Temporaneo |
Flusso pratico di una feature:
# 1. Crei un branch dalla develop
git switch develop
git switch -c feature/user-authentication
# 2. Sviluppi e committi
git add .
git commit -m "Add login form"
git commit -m "Implement JWT validation"
# 3. Integri in develop
git switch develop
git merge feature/user-authentication
# 4. Cancelli il branch
git branch -d feature/user-authentication
Questo approccio mantiene main sempre deployabile, separa lo sviluppo dalla produzione e organizza il lavoro in unità logiche.
Risolvere i conflitti di merge
Un conflitto avviene quando Git non riesce a combinare automaticamente due versioni dello stesso file. Succede quando due sviluppatori modificano le stesse righe o quando modifiche locali e remote si sovrappongono.
Come si presenta un conflitto
Quando esegui un merge con conflitti, Git ti mostra questo:
git merge feature-x
# Auto-merging index.html
# CONFLICT (content): Merge conflict in index.html
# Automatic merge failed; fix conflicts and then commit the result.
Se apri il file conflittuale, vedi questo:
<div class="header">
<<<<<<< HEAD
<h1>Benvenuto nel mio sito</h1>
=======
<h1>Welcome to my website</h1>
>>>>>>> feature-x
</div>
Come leggerlo:
<<<<<<< HEAD— Inizio della versione nel branch corrente=======— Separatore>>>>>>> feature-x— Fine della versione nel branch da mergere
Risoluzione passo-passo
# 1. Identifica i file con conflitti
git status
# 2. Apri ogni file e scegli quale versione tenere
# Rimuovi i marker (<<<, ===, >>>) e lascia solo il codice corretto
# 3. Aggiungi i file risolti
git add index.html
# 4. Completa il merge
git commit -m "Resolve merge conflict in header"
Tool visivi per i conflitti:
git mergetool— Lancia un editor grafico configurato- VS Code — Offre pulsanti "Accept Current" / "Accept Incoming"
- GitKraken, SourceTree — Client con interfacce visive
Annullare modifiche: reset, revert e restore
Git offre tre comandi per annullare cambiamenti, ognuno con comportamenti diversi.
git restore — Scarta modifiche locali (Git 2.23+)
# Scarta modifiche non staged
git restore index.html
# Rimuovi file dalla staging area (senza cancellare le modifiche)
git restore --staged index.html
git reset — Sposta il puntatore del branch
# Annulla l'ultimo commit mantenendo le modifiche
git reset --soft HEAD~1
# Annulla l'ultimo commit e rimuovi da staging
git reset --mixed HEAD~1 # (opzione di default)
# Annulla l'ultimo commit e scarta le modifiche
git reset --hard HEAD~1 # ⚠️ PERICOLOSO: cancella tutto
Quando usare reset: solo su commit NON ancora pushati. Se hai già condiviso il commit con altri, usa revert.
git revert — Crea un nuovo commit che annulla modifiche
git revert abc1234
# Crea un nuovo commit che inverte le modifiche di abc1234
Quando usare revert: sempre quando devi annullare commit pubblici. Non riscrive la storia, quindi è sicuro per i team.
Stash: metti da parte il lavoro in corso
git stash salva temporaneamente le modifiche non committate, permettendoti di cambiare branch o eseguire operazioni senza perdere lavoro.
# Salva modifiche correnti
git stash
# oppure con un messaggio
git stash save "WIP: user profile redesign"
# Lista tutti gli stash
git stash list
# stash@{0}: WIP: user profile redesign
# stash@{1}: On main: emergency fix
# Riapplica l'ultimo stash
git stash pop
# Riapplica uno stash specifico senza rimuoverlo
git stash apply stash@{1}
# Cancella tutti gli stash
git stash clear
Caso d'uso reale:
Stai lavorando su una feature ma arriva un bug critico in produzione. Invece di committare codice incompleto, fai stash, passi a un hotfix branch, risolvi, mergi, poi torni al tuo branch e fai stash pop.
.gitignore: file che Git non deve tracciare
Il file .gitignore nella root del progetto specifica quali file e cartelle Git deve ignorare. Fondamentale per evitare di committare file sensibili o generati automaticamente.
Esempio di .gitignore completo:
# Dipendenze
node_modules/
vendor/
*.log
# File di ambiente e credenziali
.env
.env.local
config/secrets.yml
# File di build
dist/
build/
*.min.js
*.min.css
# File IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS generated
.DS_Store
Thumbs.db
# Database locali
*.sqlite
*.db
Regola d'oro: aggiungi .gitignore nel primissimo commit, prima di aggiungere altri file. Molto più facile che fare cleanup dopo.
Se hai già committato file che dovrebbero essere ignorati:
# Rimuovi dal tracking ma non dal filesystem
git rm --cached file-sensibile.txt
git commit -m "Remove sensitive file from tracking"
Rebase: riscrivere la storia per una timeline pulita
git rebase riapplica i tuoi commit su un'altra base, creando una storia lineare senza merge commit. È un'operazione più avanzata ma produce cronologie molto più leggibili.
Differenza tra merge e rebase
Con merge:
A---B---C main
\ \
D---E feature
Crea un merge commit che unisce le due linee.
Con rebase:
A---B---C main
\
D'---E' feature
Riapplica D ed E dopo C, come se fossero stati creati dopo gli ultimi commit di main.
Quando usare rebase
# Aggiorna il tuo branch feature con le ultime modifiche di main
git switch feature-login
git rebase main
# Risolvi eventuali conflitti per ogni commit
# poi continua
git rebase --continue
# Oppure abbandona il rebase
git rebase --abort
⚠️ REGOLA AUREA DEL REBASE: Mai fare rebase di commit già pushati e condivisi con altri. Riscrive la storia e causa problemi ai collaboratori.
Interactive rebase: pulire i commit prima del push
# Modifica gli ultimi 3 commit
git rebase -i HEAD~3
Si apre un editor con:
pick a1b2c3d Add login form
pick e4f5g6h Fix typo
pick i7j8k9l Add validation
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# d, drop = remove commit
Puoi combinare commit piccoli, riscrivere messaggi, riordinare o eliminare commit. Perfetto per pulire il lavoro prima di aprire una Pull Request.
Tag: marcare versioni importanti
I tag sono puntatori fissi a commit specifici, usati tipicamente per le release.
# Tag semplice
git tag v1.0.0
# Tag annotato (consigliato)
git tag -a v1.0.0 -m "Release version 1.0.0"
# Lista tutti i tag
git tag
# Invia i tag al remoto
git push origin v1.0.0
# oppure tutti insieme
git push origin --tags
# Checkout di un tag specifico
git checkout v1.0.0
Convenzione Semantic Versioning:
v1.0.0— Major.Minor.Patch- Patch (0.0.1) — Bug fix retrocompatibili
- Minor (0.1.0) — Nuove feature retrocompatibili
- Major (1.0.0) — Modifiche breaking
Workflow GitHub Flow: alternativa semplificata a Git Flow
Per progetti con deployment continuo, GitHub Flow è più snello di Git Flow. Si basa su un solo branch principale (main) e feature branch di breve durata.
Processo completo:
- Crea un branch dalla
main
git switch main
git pull origin main
git switch -c feature/add-dark-mode
- Sviluppa e pusha frequentemente
git add .
git commit -m "Add dark mode toggle"
git push origin feature/add-dark-mode
- Apri una Pull Request su GitHub
- Descrizione chiara della feature
- Screenshot se riguarda UI
- Menzione degli issue collegati
- Code review e discussione
- I colleghi commentano il codice
- Fai modifiche se richieste
- Pusha gli aggiornamenti (stessa PR)
- Merge nella
maindopo approvazione
# Su GitHub clicca "Merge Pull Request"
# Oppure da locale:
git switch main
git merge feature/add-dark-mode
git push origin main
- Cancella il branch
git branch -d feature/add-dark-mode
git push origin --delete feature/add-dark-mode
Questo workflow mantiene main sempre deployabile e favorisce review del codice continue.
Best practices per commit professionali
1. Commit atomici e frequenti
Un commit = una modifica logica. Se stai scrivendo "and" nel messaggio di commit ("Fix bug and add feature"), probabilmente dovresti fare due commit.
2. Messaggi descrittivi
# ❌ Male
git commit -m "fix"
git commit -m "wip"
git commit -m "updates"
# ✅ Bene
git commit -m "Fix null pointer exception in user service"
git commit -m "Add email validation to registration form"
git commit -m "Update dependencies to resolve security warnings"
3. Non committare file generati
Build output, dipendenze, file temporanei vanno in .gitignore. Il repository deve contenere solo codice sorgente.
4. Pull prima di push
# Evita conflitti aggiornando prima
git pull origin main
git push origin main
5. Branch di vita breve
I feature branch dovrebbero vivere giorni, non settimane. Branch che restano aperti troppo a lungo divergono dalla main e causano merge difficili.
Comandi avanzati per situazioni specifiche
Cherry-pick: applicare singoli commit tra branch
# Applica il commit abc1234 dal branch X al branch corrente
git cherry-pick abc1234
Utile quando hai un fix in un branch che serve urgentemente anche in un altro, senza mergare tutto.
Bisect: trovare quale commit ha introdotto un bug
# Inizia la ricerca binaria
git bisect start
git bisect bad # Commit corrente è rotto
git bisect good v1.0.0 # Questa versione funzionava
# Git fa checkout a metà della storia
# Testi e marchi good o bad
git bisect good
# Ripeti fino a trovare il commit colpevole
git bisect reset # Torna al branch originale
Git usa ricerca binaria, quindi con 100 commit trova il bug in ~7 passaggi.
Reflog: recuperare commit "persi"
# Mostra tutte le operazioni recenti
git reflog
# Recupera un commit cancellato per sbaglio
git checkout abc1234
git switch -c recovery-branch
Il reflog è la tua rete di sicurezza — Git conserva tutto per ~90 giorni.
Git in team: strumenti e convenzioni
Pre-commit hooks
Script automatici che girano prima di ogni commit, per validare il codice:
# File .git/hooks/pre-commit
#!/bin/sh
npm run lint
npm test
Se lo script fallisce, il commit viene bloccato. Previene di pushare codice rotto.
Conventional Commits
Standard per messaggi strutturati che facilitano changelog automatici:
feat: add user authentication
fix: resolve memory leak in image processor
docs: update API documentation
refactor: simplify database query logic
Prefissi standard: feat, fix, docs, style, refactor, test, chore.
Git aliases: abbreviazioni personalizzate
# Configura alias globali
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
# Ora puoi usare:
git co main
git lg
Checklist Git per progetti professionali
Prima di considerare un progetto "production-ready", verifica questi punti:
| Check | Cosa verificare |
|---|---|
✅ .gitignore completo |
File sensibili, dipendenze e build output esclusi |
| ✅ README.md dettagliato | Setup, installazione, comandi principali documentati |
| ✅ Branching strategy definita | Git Flow o GitHub Flow adottato dal team |
| ✅ Messaggi di commit descrittivi | Niente "fix", "wip", "update" generici |
| ✅ Branch protetti | main richiede Pull Request e code review |
| ✅ CI/CD configurato | Test automatici prima del merge |
| ✅ Tag per le release | Versioning semantico con tag annotati |
Conclusione
Git è uno strumento complesso che ripaga l'investimento iniziale con produttività esponenziale. La curva di apprendimento è ripida, ma padroneggiare questi concetti — i tre stati, il branching, merge vs rebase, il workflow — trasforma Git da ostacolo a superpotere.
La chiave è iniziare semplice: clone, add, commit, push. Poi aggiungere un pezzo alla volta: i branch quando lavori su feature parallele, lo stash quando devi cambiare contesto, il rebase quando vuoi una storia pulita.
Per un developer nel 2026, saper usare Git bene non è un plus — è il requisito minimo. La differenza tra uno sviluppatore junior e uno senior spesso si vede proprio da come gestisce il version control: commit atomici, branch organizzati, conflitti risolti senza panico.
Inizia dal prossimo progetto. Crea un .gitignore decente, scrivi commit messages chiare, usa i branch per ogni feature. Sono abitudini che costruisci una volta e porti avanti per tutta la carriera.
FAQ
Qual è la differenza tra git pull e git fetch?
git fetch scarica le modifiche dal repository remoto ma non le integra nel tuo branch — aggiorna solo i riferimenti ai branch remoti. git pull esegue fetch seguito automaticamente da merge, integrando le modifiche nel tuo branch corrente. Usa fetch quando vuoi vedere cosa è cambiato prima di integrare, pull quando sei sicuro di voler aggiornare subito.
Quando devo usare merge e quando rebase?
Usa merge per integrare branch pubblici o quando vuoi preservare la storia esatta di come il lavoro è stato fatto. Usa rebase per mantenere una storia lineare e pulita, ma SOLO su branch locali non ancora condivisi. Regola aurea: mai rebase di commit già pushati e visibili ad altri sviluppatori.
Come posso recuperare un file cancellato per errore?
Se il file era tracciato da Git, puoi recuperarlo con git restore <filename> (Git 2.23+) o git checkout -- <filename> (versioni precedenti). Se hai già committato la cancellazione, usa git log -- <filename> per trovare l'ultimo commit che conteneva il file, poi git checkout <commit-hash> -- <filename> per ripristinarlo.
È sicuro usare git reset --hard?
git reset --hard cancella permanentemente tutte le modifiche non committate nella working directory e nella staging area. È sicuro solo se sei assolutamente certo di voler buttare via tutto il lavoro corrente. Prima di usarlo, considera git stash per salvare le modifiche temporaneamente, o almeno git status per vedere cosa stai per cancellare. Il reflog può recuperare commit persi, ma non modifiche mai committate.
Come funziona .gitignore con file già tracciati?
.gitignore funziona solo per file non ancora tracciati da Git. Se hai già committato un file e poi lo aggiungi a .gitignore, Git continuerà a tracciarlo. Per rimuoverlo dal tracking senza cancellarlo dal filesystem, usa git rm --cached <filename>, poi committa la modifica. Da quel momento Git lo ignorerà.
Qual è il modo migliore per annullare un commit pubblico?
Usa git revert <commit-hash> per creare un nuovo commit che annulla le modifiche. Non usare git reset su commit già pushati perché riscrive la storia e crea problemi ai collaboratori. Se hai già fatto reset e push forzato per sbaglio, comunica immediatamente al team che devono fare git pull --rebase per riallinearsi.
