Salta al contenuto principale

Gestione dei Branch Git: Locale, Remoto e Pulizia del Repository

·6 minuti
Indice dei contenuti
La gestione dei branch è una delle fonti più comuni di confusione ed errori nei workflow di team. I branch si accumulano, i remote tracking ref diventano obsoleti e le persone o eliminano la cosa sbagliata o non puliscono mai. Questo è il riferimento che vorrai salvare tra i preferiti.

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 main

I 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/login

La 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.

Avviso

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/login

Eliminare 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/login

La 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 origin

La 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 true

Con 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-nome

Per 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-nome

Se 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.

Importante

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
#

ObiettivoComando
Elimina locale (sicuro)git branch -d nome-branch
Elimina locale (forzato)git branch -D nome-branch
Elimina remotogit push origin --delete nome-branch
Elenca mergiati in maingit branch --merged main
Rimuovi ref di tracking obsoletigit fetch --prune
Rinomina branch correntegit branch -m nuovo-nome
**Tentare di eliminare il branch su cui ci si trova.** Git rifiuta con "cannot delete branch 'X' checked out at ...". Prima esegui `git switch main`. **Non eseguire il pruning dopo che i colleghi eliminano branch remoti.** Il tuo output di `git branch -r` mostra branch che non esistono più. Esegui `git fetch --prune` o imposta `fetch.prune = true` globalmente per mantenere puliti i ref di tracking. **Eliminazione forzata di lavoro non mergiato con `-D`.** Esegui sempre `git log feature/branch --oneline` prima di una eliminazione forzata per confermare di non stare buttando via commit unici. Se li hai già eliminati, controlla `git reflog` -- il SHA sarà ancora lì per 30 giorni. **Eliminare un branch mentre è aperta una PR contro di esso.** L'ordine corretto è chiudere (o mergiare) prima la PR. Eliminare il branch a metà revisione lascia i revisori in uno stato confuso sulla maggior parte delle piattaforme. **Assumere che `git push origin --delete` rimuova anche i ref di tracking locali.** Non lo fa. Hai comunque bisogno di `git fetch --prune` per rimuovere il ref obsoleto `origin/nome-branch` dal tuo repo locale.

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.

Articoli correlati