Tutorial Git: lavorare in team con i branch e il merge
verificato il 7 Settembre 2026 · 9 min
Crea un branch con git switch -c nom, lavora, poi fondilo con git merge dal branch di destinazione. In caso di conflitto Git inserisce dei marcatori nel file: scrivi il contenuto giusto, elimina i marcatori, poi git add e git commit. git merge --abort annulla tutto in qualsiasi momento.
Un branch è una linea di sviluppo parallela. Ti permette di lavorare su una funzionalità senza toccare la versione stabile, e al tuo collega di fare lo stesso dalla sua parte. Questo capitolo copre il ciclo completo: creare un branch, fonderlo, risolvere un conflitto a mano e scegliere tra merge e rebase.
git switch al posto di git checkout
Storicamente git checkout serviva a tutto: cambiare branch, crearne uno, ripristinare un file, posizionarsi su un commit preciso. Questo accumulo di ruoli è la prima fonte di confusione per chi inizia, e una fonte di incidenti per tutti gli altri.
Git 2.23, uscito ad agosto 2019, ha diviso il comando in due: git switch per spostarsi tra i branch, git restore per annullare le modifiche. All’uscita erano marcati come sperimentali, nella documentazione ufficiale non lo sono più. Questo capitolo li usa e indica sempre l’equivalente con checkout, che continuerai a incontrare a lungo nei tutorial e su Stack Overflow.
| Intenzione | Comando moderno | Forma precedente |
|---|---|---|
| Cambiare branch | git switch nom | git checkout nom |
| Creare un branch e spostarcisi | git switch -c nom | git checkout -b nom |
| Tornare al branch precedente | git switch - | git checkout - |
| Annullare la modifica di un file | git restore fichier | git checkout -- fichier |
| Togliere un file dall’indice | git restore --staged fichier | git reset HEAD fichier |
Creare un branch e lavorarci
git switch -c feature/panierSwitched to a new branch 'feature/panier'Il branch parte dal commit su cui ti trovavi. Ora puoi modificare, aggiungere e committare normalmente: niente di tutto questo comparirà su main finché non lo avrai fuso.
Sui nomi dei branch Git non impone nessuna regola, ma i prefissi feature/, fix/ e hotfix/ sono una convenzione diffusa e le interfacce delle piattaforme di hosting li raggruppano visivamente.
Per vedere a che punto sei:
git branch # i branch locali
git branch -vv # con l'ultimo commit e il branch remoto tracciato
git branch -a # locali e remoti
git switch - # tornare al branch precedentePer pubblicare il branch e renderlo visibile al team:
git push -u origin feature/panierRecuperare il branch di un collega
Nel senso opposto, git fetch aggiorna quello che sai del server senza modificare nulla nei tuoi branch:
git fetch origin feature/collegue # un branch specifico
git fetch --all # tutti i repository remoti
git branch -r # quello che sai del server origin/HEAD -> origin/main
origin/feature/collegue
origin/mainNon resta che spostarti su di esso. Git crea automaticamente il branch locale e lo collega a quello del server:
git switch feature/colleguebranch 'feature/collegue' set up to track 'origin/feature/collegue'.
Switched to a new branch 'feature/collegue'Quando Git rifiuta di cambiare branch
È uno dei primi errori che incontrerai:
error: Your local changes to the following files would be overwritten by checkout:
index.html
Please commit your changes or stash them before you switch branches.
AbortingGit protegge il tuo lavoro: il file che hai modificato non ha lo stesso contenuto sull’altro branch, e cambiare branch lo sovrascriverebbe. Tre soluzioni, in ordine di preferenza.
Committare, se il lavoro è coerente. È quasi sempre la risposta giusta, un commit imperfetto su un branch di lavoro non costa niente e si sistema più tardi con i comandi di annullamento visti nel capitolo precedente.
Mettere da parte, se il lavoro è a metà:
git stash # mette da parte le modifiche
git switch main # …fai quello che dovevi fare…
git switch -
git stash pop # recupera le modificheSaved working directory and index state WIP on main: 6d495d9 Page d accueilButtare, con git restore ., se le modifiche non valevano niente. Senza ritorno possibile.
Fondere un branch
Una volta finita la funzionalità, spostati sul branch di destinazione e fondi:
git switch main
git merge feature/panierQuando i due branch hanno modificato file diversi, Git fonde da solo e non ha niente da chiederti. Il caso interessante è l’altro.
Risolvere un conflitto
Ecco la situazione riprodotta per questo capitolo. Su feature/panier la seconda riga di index.html è stata sostituita da un messaggio di carrello vuoto. Su main la prima riga è stata modificata per aggiungere il nome del marchio. I due branch hanno toccato lo stesso file.
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.Niente è rotto. Git ha fuso quello che poteva e lascia a te il resto. Prima cosa da fare, chiedere a che punto sei:
git statusOn branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")Per ottenere solo l’elenco dei file da sistemare:
git diff --name-only --diff-filter=UApri il file. Git ci ha inserito dei marcatori:
<<<<<<< HEAD
<h1>Boutique Gekkode</h1>
<p>Bienvenue sur la boutique.</p>
=======
<h1>Boutique</h1>
<p>Votre panier est vide.</p>
>>>>>>> feature/panierLa lettura è meccanica. Tra <<<<<<< HEAD e ======= si trova la versione del branch su cui sei, qui main. Tra ======= e >>>>>>> si trova la versione del branch che stai fondendo.
Tocca a te scrivere il risultato corretto. Non è per forza l’una o l’altra: qui le due modifiche sono entrambe valide e devono convivere.
<h1>Boutique Gekkode</h1>
<p>Votre panier est vide.</p>Elimina i tre marcatori, non devono restare nel file. Poi segnala a Git che è risolto e concludi la fusione:
git add index.html
git commit -m "Fusionne feature/panier dans main"* 0899b0c Fusionne feature/panier dans main
|
| * aacf4c0 Panier : message quand le panier est vide
* | 11ff16b Ajoute le nom de la marque au titre
|/
* 6d495d9 Page d accueilIl commit di merge ha due genitori, e il grafo lo rende visibile.
Annullare tutto e ripartire da zero
Se il conflitto ti sfugge di mano, non sei obbligato a niente:
git merge --abortIl repository torna esattamente allo stato precedente al comando merge. Non si perde niente: puoi ricominciare più tardi o parlarne con l’autore dell’altro branch.
merge o rebase
Entrambi integrano il lavoro di un branch in un altro, ma non allo stesso modo.
git merge crea un commit di merge che collega le due cronologie. La cronologia conserva la traccia esatta di quello che è successo, compreso il fatto che due branch sono esistiti in parallelo. Il grafo è fedele, ma si ramifica.
git rebase riapplica i tuoi commit sopra il branch di destinazione, come se avessi lavorato a partire dalla sua ultima versione. La cronologia resta una linea dritta, più facile da leggere, ma viene riscritta: i tuoi commit cambiano identificativo.
git switch feature/panier
git rebase mainUn rebase può incontrare gli stessi conflitti di una fusione, commit per commit. La risoluzione è identica, cambia solo il comando per proseguire:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 4937109... Promo
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 4937109... Promogit add index.html
git rebase --continue
# oppure, per annullare tutto
git rebase --abortLa regola d’oro sta in una frase: non fare mai il rebase di un branch che altre persone hanno già scaricato. Riscrivere una cronologia condivisa obbliga i tuoi colleghi a riparare la loro a mano. Sul tuo branch di lavoro, prima di proporlo, il rebase è invece perfettamente legittimo e restituisce una cronologia molto più leggibile.
Il caso quotidiano: qualcuno ha pushato prima di te
Vuoi fare push e Git rifiuta:
To /root/o.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '/root/o.git'
hint: Updates were rejected because the remote contains work that you do notIl server ha commit che tu non hai. Devi prima integrarli. E qui, su un repository nuovo, Git ti fa una domanda invece di agire:
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:Dalla versione 2.27 Git si rifiuta di scegliere al posto tuo. Rispondi una volta per tutte, come proposto nel capitolo sull’installazione:
git config --global pull.rebase trueLo svolgimento diventa allora questo:
git pull --rebase
git pushFrom /root/o
622a60b..38b7dc5 main -> origin/main
Rebasing (1/1)Successfully rebased and updated refs/heads/main.
* 5b45117 Ajoute app.js
* 38b7dc5 Ajoute la doc
* 622a60b DepartIl tuo commit è stato riposizionato sopra quello del collega e la cronologia è rimasta lineare, senza commit di merge parassita. È l’impostazione da consigliare a un team che inizia.
Un avvertimento per finire: non provare mai a sbloccare un push rifiutato con git push --force. Questo comando sovrascrive il lavoro presente sul server. Se devi davvero forzare, dopo il rebase di un tuo branch, usa git push --force-with-lease, che si rifiuta di sovrascrivere commit che non avevi visto.
Fare pulizia
Un ramo fuso non ha più motivo di esistere. Se è stato pubblicato con -u, spingete prima i suoi ultimi commit: Git si rifiuta di eliminare un ramo locale in anticipo sul suo ramo remoto, anche se fuso in main.
git push origin feature/panier
git branch -d feature/panierDeleted branch feature/panier (was bc2203a).Senza quel push preliminare, il messaggio è esplicito:
warning: not deleting branch 'feature/panier' that is not yet merged to
'refs/remotes/origin/feature/panier', even though it is merged to HEAD
error: the branch 'feature/panier' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/panier'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Se il branch non è stato fuso, Git ti ferma, ed è una rete di sicurezza utile:
error: the branch 'feature/promo' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/promo'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Per eliminare il branch anche sul server e ripulire i riferimenti locali ormai obsoleti:
git push origin --delete feature/panier
git fetch --prunegit fetch recupera lo stato del server senza fondere niente nei tuoi branch, a differenza di git pull. L’opzione --prune elimina di passaggio i branch remoti che non esistono più, quelli che i tuoi colleghi hanno fuso e cancellato.
Ora sai collaborare. L’ultimo capitolo parla di organizzazione: quale modello di branch adottare in base al tuo team.
Errori frequenti
git stash, prima di cambiare branch.git pull si rifiuta di scegliere da solo tra fusione e rebase. Chiudi la questione con git config --global pull.rebase true.git pull --rebase. Non usare mai git push --force per aggirare il problema: sovrascrive il lavoro degli altri.<<<<<<<, ======= e >>>>>>> devono sparire dal file prima del git add.