Introduzione
In Git, un branch è solo un riferimento spostabile a un commit. Creare un branch è creare un file di 41 byte. Rispetto ai sistemi centralizzati dove i branch sono copie complete di directory, il modello di Git rende il branching abbastanza economico da usare con disinvoltura.
Cosa è realmente un branch
cat .git/refs/heads/main
# a1b2c3d4e5f6...
git rev-parse main
Quell'hash è la punta del branch. Il "branch" stesso è la catena di commit raggiungibili dalla punta tramite i puntatori parent.
Creare branch
git branch feature/login # crea, non passare
git switch -c feature/login # crea e passa
git switch -c hotfix v1.2.3 # da un tag
git branch fixup HEAD~3 # da un ref relativo
Spostare la punta
Ogni commit sul branch corrente ne avanza la punta di uno. I comandi che spostano le punte includono commit, merge, rebase, reset e cherry-pick.
git commit -m "Work" # main si muove avanti
git reset --hard HEAD~2 # main si muove indietro; i commit diventano irraggiungibili
Branch e raggiungibilità
Un commit è "vivo" finché qualche ref lo raggiunge. Cancella ogni branch e tag che punta a un commit ed esso diventa dangling; il garbage collector di Git alla fine lo rimuove.
git fsck --unreachable
git gc
Tracciare l'upstream
Un branch locale può essere collegato a un branch di tracking remoto:
git branch --set-upstream-to=origin/main main
git branch -u origin/main
git status # mostra ahead/behind in base al collegamento
Manutenzione dei branch
git branch --merged main # branch completamente mergiati
git branch --no-merged main # branch con lavoro non mergiato
git branch -d feature/old # cancella mergiato
git branch -D feature/discarded # forza cancellazione
Confrontare branch
git log main..feature/login --oneline
git diff main...feature/login
git range-diff main..@{u} main..HEAD
range-diff è ottimo per confrontare due versioni di un branch rebasato.
Politiche di branch sugli host
La maggior parte delle piattaforme di hosting ti permette di proteggere i branch per pattern di nome: richiedere pull request, commit firmati, CI passing o reviewer specifici prima che un push sia accettato. Il lato Git di questo è implementato tramite hook pre-receive; il lato piattaforma è configurazione. Dal tuo clone locale, la protezione del branch è invisibile finché il tuo push non viene rifiutato, momento in cui il server spiega perché. Per ispezionare la protezione dalla riga di comando, usa la CLI dell'host (gh, glab) o la sua API.
gh api repos/owner/repo/branches/main/protection
Errori comuni
Immaginare i branch come contenitori di commit. Non lo sono; i commit esistono indipendentemente e molti branch possono raggiungere lo stesso commit. Cancellare un branch "feature" e assumere che i commit siano spariti; sono spariti solo dopo che diventano irraggiungibili e il reflog scade (90 giorni di default). Usare nomi di branch a parola singola lunga che si scontrano con nomi di file; i separatori -- evitano l'ambiguità. Infine, lavorare direttamente su main in un repo condiviso; ramifica sempre per lavoro non triviale, anche se prevedi di fare fast-forward dopo.