Articolo originale: https://www.freecodecamp.org/news/the-ultimate-guide-to-git-merge-and-git-rebase/

Benvenuto nella nostra guida definitiva ai comandi git merge e git rebase. Questo tutorial ti insegnerà tutto quello che devi sapere per combinare più branch con Git.

Git Merge

Il comando git merge incorporerà nel tuo branch corrente tutte le modifiche fatte sul codice in un branch diverso, sotto forma di nuovo commit.

La sintassi del comando è la seguente:

git merge NOME-BRANCH

Per esempio, se stai attualmente lavorando in un branch chiamato dev e vorresti incorporare tutte le nuove modifiche fatte in un branch chiamato new-features, dovrai eseguire il seguente comando:

git merge new-features

Nota: Git non ti consentirà l'azione di merge se nel tuo branch corrente ci sono modifiche per le quali non hai ancora eseguito l'azione di commit. Per gestire queste modifiche puoi in alternativa:

  • Creare un nuovo branch ed eseguire il commit delle modifiche
git checkout -b nome-nuovo-branch
git add .
git commit -m "<il tuo messaggio di commit>"
  • Accantonarle
git stash               # accantona nell'area di stash
git merge new-features  # esegui le tue incorporazioni
git stash pop           # recupera nuovamente la modifiche nella tua alberatura di lavoro
  • Abbandonare tutte le modifiche
git reset --hard        # elimina tutte le modifiche in sospeso

Git Rebase

L'azione di rebase di un branch in Git è un modo per spostare un intero branch in un altro punto nell'alberatura. L'esempio più semplice è spostare un branch più in alto nell'alberatura. Diciamo che abbiamo un branch che si discosta dal branch master al punto A:

        /o-----o---o--o-----o--------- branch
--o-o--A--o---o---o---o----o--o-o-o--- master

Quando esegui l'azione di rebase puoi spostarlo in questo modo:

                                   /o-----o---o--o-----o------ branch
--o-o--A--o---o---o---o----o--o-o-o master

Per effettuare il rebase, assicurati di avere tutti i commit che vuoi portarti nel rebase nel tuo branch master. Entra (checkout) nel branch per il quale vuoi effettuare l'azione di rebase ed esegui git rebase master (dove master è il branch verso il quale vuoi effettuare lo spostamento).

È anche possibile effettuare il rebase su un branch diverso, in modo che, per esempio, un branch basato su un altro branch (chiamiamolo "feature") sia spostato sul master:

                            /---o-o branch
           /---o-o-o-o---o--o------ feature
----o--o-o-A----o---o--o-o-o--o--o- master

Dopo git rebase master branch oppure git rebase master se sei entrato nel branch, otterrai:

           /---o-o-o-o---o--o------ feature
----o--o-o-A----o---o--o-o-o--o--o- master
                                  \---o-o branch

Git rebase interattivo nella console

Puoi usare git rebase con l'opzione -i, iniziando in questo modo un'azione interattiva nella console, con un elenco di commit che puoi scegliere, modificare, o scartare nel rebase:

  • Digita git rebase -i HEAD~5, con l'ultimo numero che corrisponde a quanti commit vuoi esaminare all'indietro rispetto al più recente.
  • Si aprirà il tuo editor predefinito con un testo che puoi iniziare a modificare
  • Sul lato sinistro, puoi sovrascrivere la parola  pick con uno dei comandi qui sotto. Se vuoi raggruppare un commit con uno precedente e scartare il messaggio di commit, inserisci f al posto di pick per quel commit.
  • Salva ed esci dall'editor di testo, a questo punto git inizierà a rieseguire i commit utilizzando i comandi di rebase specificati al punto precedente.
  • Se il rebase si ferma, esegui gli aggiustamenti necessari, poi usa git rebase --continue fino a che l'azione di rebase non si conclude positivamente.
  • In caso di successo, devi forzare l'invio delle tue modifiche con git push -f per aggiungere la versione dopo il rebase al tuo repository remoto.
  • Se c'è un conflitto nell'azione di merge, ci diversi modi per sistemarlo, compreso il seguire le istruzioni di questa guida (in lingua inglese). Un modo è aprire i file in un editor di testo ed eliminare le parti di codice indesiderate. Poi usa git add <nome file> seguito da git rebase --continue. Puoi saltare il commit che causa conflitto digitando git rebase --skip, oppure interrompere l'azione di rebase digitando nella console git rebase --abort.
N.d.T.
La descrizione dei comandi di rebase nel testo che segue è stata tradotta per una migliore comprensione dell'esposizione, ma nella realtà è in lingua inglese.
pick 452b159 <messaggio per questo commit>
pick 7fd4192 <messaggio per questo commit>
pick c1af3e5 <messaggio per questo commit>
pick 5f5e8d3 <messaggio per questo commit>
pick 5186a9f <messaggio per questo commit>

# Rebase 0617e63..5186a9f onto 0617e63 (30 comandi)
#
# Comandi:
# p, pick = usa il commit
# r, reword = usa il commit, ma interrompi la modifica del  messaggio di commit.
# e, edit = usa il commit, ma interrompi l'amend e interrompi la modifica del messaggio di commit.
# s, squash = usa il commit, uniscilo al commit precedente e interrompi la modifica del messaggio di commit
# f, fixup = come "squash", ma scarta il messaggio di questo commit, pertanto non interrompe.
# x, exec = esegui il comando (il resto della riga) usando la shell
# d, drop = rimuovi il commit
#
# Queste righe possono essere riordinate, vengono eseguite dall'inizio alla fine. 
#
# Se elimini una riga di commit QUEL COMMIT VERRÀ PERDUTO.
#
# Tuttavia, se elimini tutto, l'azione di rebase verrà interrotte.
#
# Nota che i commit vuoti sono commentati (esclusi)

Conflitti in Merge

Un conflitto in merge è quando esegui commit in branch separati che modificano la stessa riga in maniera conflittuale. Se questo accade, Git non saprà quale versione del file mantenere e stamperà un messaggio di errore simile al seguente:

CONFLICT (content): Merge conflict in resumé.txt Automatic merge failed; fix conflicts and then commit the result.

Se osservi il file resumé.txt citato nel messaggio nel tuo editor testi, vedrai dove avviene il conflitto:

<<<<<<< HEAD
Address: 808 South Street
=======
Address: 505 North Street
>>>>>>> updated_address

Git ha aggiunto alcune righe al file:

  • <<<<<<< HEAD
  • =======
  • >>>>>>> updated_address

Pensa a ======= come la riga che divide il conflitto. Tutto quello che sta fra <<<<<<< HEAD e ======= è il contenuto nel branch corrente al quale il riferimento HEAD sta puntando. Mentre tutto quello che sta tra  ======= e >>>>>>> updated_address è il contenuto nel branch che si sta incorporando, updated_address.

Git Merge vs Git Rebase

Sia git merge che git rebase sono comandi molto utili, e uno non è migliore dell'altro. Tuttavia ci sono alcune differenze molto importanti tra i due comandi che tu e la tua squadra dovreste tenere in considerazione.

Ogniqualvolta git merge viene eseguito, viene creato un commit di merge supplementare. Ogni volta che lavori nel tuo repository locale, avere troppi commit di merge potrebbe rendere confusa la cronologia dei commit. Un modo per evitare il commit di merge è usare invece git rebase.

git rebase è una funzionalità molto potente. Ciò detto, è anche rischiosa se non usata nel giusto modo. git rebase altera la cronologia dei commit, quindi usalo con cautela. Se il rebase viene fatto nel repository remoto, allora può creare molti problemi quando gli altri sviluppatori tentano di ottenere le ultime modifiche al codice dal repository remoto. Ricorda di eseguire git rebase in un repository locale.

Questo è tutto ciò che devi sapere per eseguire al meglio merge e rebase.