1. Che cosa sono i rami e a cosa servono?
Lavorare con le branches in Git è uno degli aspetti chiave del controllo di versione, che consente di sviluppare in parallelo più linee di lavoro all’interno dello stesso repository. Il branching rende Git uno strumento potente per la collaborazione, la sperimentazione e la gestione delle diverse versioni di un progetto.
gitGraph
commit id: "Initial setup"
commit id: "Add base features"
branch feature/new-idea
checkout feature/new-idea
commit id: "Implement new logic"
commit id: "Refactor the logic"
checkout main
commit id: "Urgent bugfix on main"
merge feature/new-idea
commit id: "Prepare for release"
main si dirama una nuova branch,
feature/new-idea, per uno sviluppo sicuro. Al termine del lavoro, viene fusa di nuovo in
main.
Immaginate di voler ristrutturare seriamente il vostro progetto o effettuare un esperimento rischioso. Come fareste senza Git? Probabilmente copiereste l’intero progetto in una nuova cartella e lavorereste lì. Se il risultato vi piacesse — lo portereste nella cartella principale. In caso contrario — eliminereste semplicemente la copia.
I rami in Git funzionano secondo lo stesso principio, ma in modo molto più elegante. Vediamolo con l’esempio della scrittura di un libro:
- Avete un manoscritto pronto (questo è il vostro ramo principale
main). - Volete scrivere un finale alternativo (create un nuovo ramo, per esempio
feature/new-idea). - Scrivete il nuovo finale senza toccare il testo principale del manoscritto (lavorate nel nuovo ramo).
- Se il nuovo finale risulta migliore, lo sostituite al vecchio (eseguite il merge dei rami —
merge). - Il vecchio abbozzo con il finale inutile può essere eliminato (cancellate il ramo).
2. Creare un nuovo ramo e lavorarci
Passo 1. Aprite il menu di gestione dei rami.
Nella barra superiore dell’IDE c’è un widget che mostra il nome del ramo corrente (per impostazione predefinita — main). Fate clic su di esso e scegliete + New Branch.
Passo 2. Nome del nuovo ramo.
È buona pratica dare ai rami un nome in linea con il task che state risolvendo. Per esempio, feature/add-usage-examples.
Dopo la creazione del ramo, l’IDE si sposterà automaticamente su di esso. Vedrete il nuovo nome nello stesso widget.
Passo 3. Apportate le modifiche ed effettuate il commit.
Ora vi trovate nella vostra “sandbox”. Aggiungiamo al nostro file README.md una nuova sezione con esempi d’uso. Apportate le modifiche ed effettuate il commit, come avete imparato nella lezione precedente.
3. Passare da un ramo all’altro
Le vostre modifiche con gli esempi d’uso sono ora salvate in modo affidabile nel ramo feature/add-usage-examples. Torniamo al ramo principale main e vediamo cosa c’è lì.
Passo 1. Fate di nuovo clic sul widget con il nome del ramo corrente.
Passo 2. Nell’elenco Local o Recent scegliete il ramo main e, nel sottomenu che appare, fate clic su Checkout.
Passo 3. Verificate il risultato.
Non appena passate di ramo, aprite il file README.md. Vedrete che la sezione con gli esempi d’uso qui non c’è! È rimasta nell’altro ramo. In questo modo potete lavorare su nuove funzionalità senza toccare la versione stabile nel ramo main.
4. Unione dei rami (Merge)
Il comando merge prende tutti i commit dal ramo feature/add-examples (in questo caso, il commit C3) e li unisce con il ramo corrente main, creando un nuovo commit di merge.
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/add-examples
checkout feature/add-examples
commit id: "C3: Add new section"
checkout main
merge feature/add-examples
Dunque, avete terminato il lavoro sul vostro task nel ramo feature/add-usage-examples e volete aggiungere queste modifiche al progetto principale.
Passo 1. Passate al ramo di destinazione.
Assicuratevi di trovarvi nel ramo DOVE volete aggiungere le modifiche. Nel nostro caso è main.
Passo 2. Eseguite il merge.
Fate di nuovo clic sul widget di gestione dei rami. Nell’elenco scegliete il ramo DA DOVE volete prendere le modifiche (feature/add-usage-examples) e nel sottomenu scegliete Merge feature/add-usage-examples in main.
Passo 3. Verificate il risultato.
Ora nel file README.md del ramo main è comparsa la vostra nuova sezione con esempi. Avete unito con successo il vostro lavoro con la versione principale del progetto!
5. Conflitti durante il merge: niente paura, è normale!
A volte durante il merge dei rami sorgono dei conflitti. Ciò accade quando in entrambi i rami sono state modificate le stesse righe nello stesso file. Git non può decidere da solo quale versione sia corretta e chiede il vostro aiuto.
gitGraph
commit id: "C1: Base comune"
branch feature/new-title
checkout main
commit id: "C2: Modifica in main"
checkout feature/new-title
commit id: "C3: Modifica in feature"
main e
feature/new-title, hanno nuovi commit (C2 e C3) basati su un antenato comune (C1). Questo porterà sicuramente a un conflitto durante il merge.
Simuliamo un conflitto:
- Assicuratevi di trovarvi nel ramo
maine di non avere modifiche non salvate. - Create subito un nuovo ramo
feature/new-title, ma non passateci ancora. Assicuratevi che la spunta Checkout branch sia disattivata. - Ora, trovandovi nel ramo
main, cambiate la prima riga inREADME.mdin “My Awesome Project” ed effettuate ilcommit. - Passate al ramo
feature/new-title. Vedrete che la prima riga inREADME.mdqui è rimasta quella vecchia: è lo stato del file al momento della creazione del ramo. Cambiate la stessa riga in “My Super Project” ed effettuate ilcommit. - Tornate al ramo
mained eseguite il merge confeature/new-title.
Ora Git vedrà che entrambi i rami hanno storie nuove e divergenti a partire dal loro antenato comune. In entrambe le storie è stata modificata la stessa riga, quindi Git non potrà scegliere quale versione sia corretta e vi mostrerà una finestra per la risoluzione del conflitto.
Merge Revision
Cosa vedete qui:
- A sinistra (Your changes): la versione del file dal vostro ramo corrente (
main). - A destra (Changes from branch...): la versione del file dal ramo che state fondendo.
- Al centro (Result): la versione finale del file che dovete comporre.
Potete fare clic sulle frecce >> o << per accettare interamente una delle due varianti.
Quando il risultato nel pannello centrale vi soddisfa, fate clic su Apply. L’IDE creerà automaticamente un commit di merge e il conflitto sarà risolto.
Perché non si è verificato un conflitto?
Può capitare che abbiate eseguito tutti i passaggi e che non sia sorto alcun conflitto. Molto spesso ciò accade perché Git è riuscito a eseguire un fast-forward merge, dato che la storia di un ramo ha semplicemente proseguito la storia dell’altro. Affinché il conflitto sia garantito, le storie dei rami devono divergere in direzioni diverse a partire dall’antenato comune.
Esempio:
- Avete un commit in
main(supponiamo, C1). - Fate un nuovo commit in
maincon il testo “My Awesome Project”. Il ramomainora punta al commit C2 (main -> C1 -> C2). - Create il ramo
feature/new-titledalla posizione corrente di main. Questo significa che il nuovo ramo inizia anch’esso dal commit C2. - Fate un commit in
feature/new-titlecon il testo “My Super Project”. Questo ramo “va avanti” e ora punta al commit C3 (feature/new-title -> C1 -> C2 -> C3). - Tornate in
main(che è ancora al commit C2) e date il comando di fondere feature/new-title.
Git guarda la situazione e vede che il ramo main è un antenato diretto del ramo feature/new-title. Nella storia di main non ci sono stati nuovi commit mentre lavoravate nell’altro ramo. Git pensa: “Ah, qui basta far avanzare main fino al commit C3. Nessuna contraddizione”. E sposta semplicemente il puntatore di main al commit C3.
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/new-title
checkout feature/new-title
commit id: "C3"
checkout main
merge feature/new-title
6. Visualizzare la cronologia delle modifiche
Per comprendere meglio cosa sta accadendo nel vostro progetto, è utile guardare la sua cronologia.
Aprite la scheda Git nella parte inferiore dell’IDE e scegliete Log. Vedrete una rappresentazione grafica di tutti i vostri rami e commit. Questo aiuta a capire chiaramente da quale ramo si è staccato quale e dove sono stati fusi.
Qui potete fare clic su qualsiasi commit per vedere quali modifiche contiene, chi lo ha effettuato e quando. È una vera e propria macchina del tempo per il codice!
GO TO FULL VERSION