Dopo qualche mese su un repository condiviso, la lista dei branch inizia a sembrare uno scavo archeologico. Ci sono branch di feature per ticket chiusi sei mesi fa, un hotfix-DO-NOT-DELETE che nessuno osa toccare e una dozzina di ref origin/feature-* per branch che non esistono più sul remote. Capire esattamente come branch locali, branch remoti e remote tracking ref si relazionano tra loro è la base per tenere tutto sotto controllo.
Il Modello Mentale: Branch Locali vs Remote Tracking Branch#
Prima di toccare qualsiasi comando di eliminazione, è utile avere un quadro chiaro di ciò che Git memorizza effettivamente.
graph LR
subgraph "Il Tuo Computer"
A[main] -->|traccia| B[origin/main]
C[feature-x] -->|traccia| D[origin/feature-x]
E[old-branch]
end
subgraph "GitHub / GitLab"
F[main]
G[feature-x]
end
B -.->|ultimo stato fetchato di| F
D -.->|ultimo stato fetchato di| G
origin/main non è il branch remoto stesso. È la tua copia locale di come appariva il remote l’ultima volta che hai eseguito git fetch. Questa distinzione è importante quando inizi a rimuovere ref obsoleti.
Elencare i Branch#
Prima di eliminare qualsiasi cosa, sappi cosa hai.
# Solo branch locali
git branch
# Solo remote tracking branch
git branch -r
# Tutti i branch (locali + remote tracking)
git branch -a
# Branch già mergiati in main
git branch --merged main
# Branch non ancora mergiati in main
git branch --no-merged mainI filtri --merged e --no-merged sono il modo più sicuro per identificare cosa è sicuro rimuovere. Qualsiasi branch in --merged main ha già il suo lavoro incorporato, quindi i commit non vanno da nessuna parte anche se elimini il puntatore al branch.
Eliminare Branch Locali#
# Eliminazione sicura: rifiuta se il branch non è completamente mergiato
git branch -d feature/login
# Eliminazione forzata: bypassa il controllo del merge
git branch -D feature/loginLa distinzione tra -d e -D non è arbitraria. -d è una protezione: Git verifica se la punta del branch che vuoi eliminare è raggiungibile da HEAD o dal branch di tracking upstream. Se la risposta è no, rifiuta. -D bypassa completamente quel controllo.
git branch -D su lavoro non mergiato distrugge commit che non sono raggiungibili da nessun altro ref. Il reflog ti salverà per 30 giorni, ma dopo di ciò gli oggetti vengono eliminati dal garbage collector. Non forzare l’eliminazione senza prima verificare con git log feature/branch --oneline.
Non puoi eliminare il branch su cui sei attualmente. Prima passa a main (o qualsiasi altro branch):
git switch main
git branch -d feature/loginEliminare Branch Remoti#
Ci sono due sintassi che ottengono lo stesso risultato:
# Sintassi moderna ed esplicita (preferita)
git push origin --delete feature/login
# Sintassi legacy con i due punti (funziona ancora, stesso effetto)
git push origin :feature/loginLa sintassi con i due punti deriva dal formato refspec di Git: src:dst. Un src vuoto significa “non pushare nulla a questa destinazione”, il che elimina il ref sul remote. Vale la pena conoscerla perché la incontrerai in script e documentazione più vecchi.
Eliminare un branch remoto non rimuove automaticamente il ref di tracking origin/feature/login dal tuo repository locale. Questo richiede il pruning.
Rimozione dei Remote Tracking Ref Obsoleti#
Una volta eliminato un branch sul remote, il tuo ref locale origin/feature/login rimane orfano. Punta a un remote che non esiste più. Git chiama questi ref “stale”.
# Fetch e pruning in un solo passaggio (consigliato per l'uso quotidiano)
git fetch --prune
# Pruning senza scaricare nuovi aggiornamenti
git remote prune originLa differenza: git fetch --prune contatta il remote, scarica i nuovi ref e rimuove i remote tracking ref locali che non sono più sul remote. git remote prune origin rimuove solo i ref di tracking obsoleti, non scarica nulla di nuovo. Per la maggior parte dei workflow, git fetch --prune è quello che vuoi.
Puoi anche configurare Git per eseguire il pruning automaticamente ad ogni fetch:
git config --global fetch.prune trueCon questa impostazione, git fetch si comporta come git fetch --prune ovunque.
Rinominare Branch#
Rinominare un branch locale è semplice:
# Rinominare il branch corrente
git branch -m nuovo-nome
# Rinominare un branch specifico (mentre sei su un branch diverso)
git branch -m vecchio-nome nuovo-nomePer propagare la rinomina al remote, devi pushare il nuovo nome ed eliminare quello vecchio:
git push origin nuovo-nome
git push origin --delete vecchio-nome
# Aggiorna il tracking upstream per il tuo branch locale
git branch --set-upstream-to=origin/nuovo-nome nuovo-nomeSe il tuo team ha aperto una pull request contro il vecchio nome del branch su GitHub o GitLab, la rinomina richiederà l’aggiornamento del branch base della PR prima di eliminare il ref remoto vecchio.
Proteggere i Branch dall’Eliminazione Accidentale#
Le regole di protezione dei branch a livello di piattaforma sono la tua ultima linea di difesa contro gli errori che git branch -D non può proteggere.
Su GitHub: Settings > Branches > Branch protection rules. Seleziona “Restrict deletions” per impedire a chiunque (inclusi gli admin) di pushare un delete ref per il branch protetto.
Su GitLab: Settings > Repository > Protected branches. Imposta “Allowed to delete” su “No one” per branch come main e release.
Le regole di protezione dei branch non impediscono l’eliminazione locale con git branch -D. Bloccano solo il git push --delete che rimuoverebbe il branch dal remote. I branch locali sono sempre sotto il tuo controllo.
Riferimento Rapido#
| Obiettivo | Comando |
|---|---|
| Elimina locale (sicuro) | git branch -d nome-branch |
| Elimina locale (forzato) | git branch -D nome-branch |
| Elimina remoto | git push origin --delete nome-branch |
| Elenca mergiati in main | git branch --merged main |
| Rimuovi ref di tracking obsoleti | git fetch --prune |
| Rinomina branch corrente | git branch -m nuovo-nome |
Se vuoi approfondire uno qualsiasi di questi argomenti, offro sessioni di coaching 1:1 per ingegneri che lavorano su integrazione AI, architettura cloud e platform engineering. Prenota una sessione (50 EUR / 60 min) o scrivimi a manuel.fedele+website@gmail.com.