Git branching and merging

Oggi mostreremo alcuni esempi veramente basilari di come usare il prompt di git per creare dei branch e fare dei merge.

Come sapete il Pro Git Book, scritto da Scott Chacon, è interamente leggibile online qui

Vi siete mai chiesti qual è la storia di Git? Qui un breve excursus. Ma quello ancora più interessante è che Git prende il nome sempre da Linus Torvalds. Dopo aver dato il proprio nome ad uno dei sistemi operativi più diffusi, ha voluto descrivere nel progetto di Version Control anche un’aspetto della sua personalità. Da qui nasce il termine Git che in slang sta a significare una persona “poco simpatica” 🙂 (Wikipedia, Urban Dictionary).

Bene dopo un po’ di storia, sempre divertente (molto spesso le persone utilizzano gli strumenti ma non si chiedono il perché del loro nome o da dove sono “arrivati”) passiamo alla pratica.

Bene creiamo la cartella “git_merge” e inizializziamo in essa un repository Git.

Creiamo quindi il file “hello.py” seguente:

#! /usr/bin/env python

def hello():
    print "Hello World!\n"

hello()

lo rendiamo eseguibile

chmod +x hello.py

e lo aggiungiamo al repository

git add hello.py
git commit -m 'added hello.py'

A questo punto creiamo un “branch” e lo chiamiamo “refactoring” e ci spostiamo in esso.

git branch refactoring
git checkout refactoring

e modifichiamo il file cambiamo il nome della funzione hello() in say_hello() e committiamo.

A questo punto decidiamo che il rename della funzione ci piace di più e vogliamo quindi fare il merge di ‘refactoring’ nel ‘master’.

git checkout master
git merge refactoring

In questo caso il merge è semplice e viene fatto il cosiddetto fast-forward. Ovvero master viene portato avanti nel nodo di refactoring. In parole povere il merge è automatico.

Visualizzando il grafico del log, non si vedono “rami” in quanto sia ‘master’ che ‘refactoring’ puntano allo stesso ‘nodo’ nella struttura dei commit.

Adesso, modifichiamo il file hello.py nel master aggiungendo il commento alla funzione say_hello()

Poi passiamo al branch refactoring in cui invece modifichiamo la funzione say_hello() in greetings() e aggiungiamo anche un parametro in ingresso.

A questo punto decidiamo di voler mettere il parametro in ingresso anche in master e quindi facciamo un merge.

git checkout master
git merge refactoring

E ta-dan! Git questa volta non riesce in automatico a risolvere i conflitti perché non sa quale sia la modifica che si vuole tenere e quale quella da eliminare.

Il file hello,py viene modificato nel seguente modo:

Cosa vediamo? 🙂

Una cosa che ci fa paura… allora digitiamo

git merge --abort

E tutto tornerà come prima.

Se invece vogliamo procedere al merge allora dobbiamo conoscere i seguenti simboli

<<<<<<<<

Da questo simbolo fino al successivo, vediamo il file presente nella HEAD del repository su cui siamo, in questo caso master. Abbiamo infatti il nostro commento alla funzione.

|||||||||

Da questo simbolo al successivo vi è la precedente versione del file (quella della commit precedente) rispetto al repository in cui ci troviamo, quindi master.

Quindi se guardiamo questa parte centrale e la parte in alto avremo le differenze tra il file corrente nel repository master e quello della commit precedente.

========

Da questo simbolo fino al successivo (ultimo) abbiamo il file del branch da cui vogliamo fare il merge, in questo caso: refactoring.

Quindi se guardiamo la parte centrale e la parte in basso avremo le differenze tra il file corrente nel branch e quello della commit precedente nel master.

>>>>>>>>

Tutto quello che sta fuori, è quello che Git ha deciso di tenere e non sta considerando come un conflitto.

 

Quindi… se vogliamo tenere il file nel master basta tenere la parte tra <<<<<< e |||||| e cancellare tutto il resto compresi questi simboli.

Se vogliamo tenere il file del branch refactoring basta tenere la parte tra ====== e >>>>>> e cancellare tutto il resto compresi questi simboli.

Se invece, come faremo, vogliamo tenere un po’ di una parte e un po’ dell’altra, andremo ad integrare la parte centrale con le aggiunte (o riscrivete il file, come vi piace di più) della parte sopra e della parte sotto.

Ecco alla fine come abbiamo modificato il file.

#! /usr/bin/env python

def greetings(who):
    """ Say hello to the World! """
    print "Hello, " + who

greetings("Fabio")

A questo punto facciamo la commit.

Fine 🙂

Da qui in poi invece leggete solo se siete curiosi.

Se quando abbiamo avuto dei conflitti avessimo voluto isolare le tre sezioni in file differenti per poi farne i diff tra di loro, avremmo potuto eseguire i seguenti comandi:

git show :1:hello.py > hello.base.py
git show :2:hello.py > hello.head.py
git show :3:hello.py > hello.refactoring.py

A questo punto se volete fare il diff tra di loro si può fare per esempio:

git diff --no-index hello.base.py hello.refactorug.py

E una volta terminata la vostra correzione dei conflitti nel file hello.py potete pulire tutto con

git clean -f

Okay, okay… voi utilizzate il tool grafico, ma… sapere come funziona sotto non è bello?! 😀

Git branching and merging