In questa nuova guida, utile a tutti gli iPhone e iPad developers (ma non solo) non parleremo di programmazione vera e propria, ma vedremo come utilizzare e sfruttare al meglio un utile strumento / servizio durante lo sviluppo delle nostre applicazioni iOS: git, una delle migliori alternative a Mercurial o Subversion, che ci aiuterà a tenere ordine tra le diverse versioni dei nostri progetti e a lavorare in team con altri sviluppatori. Oggi vedremo come utilizzare git via terminale ma, prima di addentrarci nella pratica, scopriamo insieme di cosa si tratta.
“Git is a free & open source, distributed version control system designed to handle everything from small to very large projects with speed and efficiency.”
Cos’è git?
Questa è la descrizione che offrono i creatori di git sul loro sito http://git-scm.com/. Il nodo cruciale di questa definizione è “version control system” e se se ne ignora il significato tutto resta piuttosto oscuro.
Cos`è, quindi, un “version control system”? Se mi è perdonata la tautologia un “version control system” è un “version control system”, nient’altro! Non è un tool di backup, non è un modo per condividere un progetto ma è solo un sistema per mantenere il controllo delle versioni. Mantenere il controllo delle versioni ci aiuta poi in altri aspetti come appunto la condivisione di un progetto e le copie di backup, ma è bene non confondere i ruoli.
Git è quindi un sistema di controllo delle versioni, significa quindi che riesce a mantenere memoria degli stati precedenti dei nostri progetti. Chiaramente git non si limita solo a questo ma fa anche molto altro e lo vedremo lungo l’articolo.
Git non è l’unico software per il controllo di versione, ne esistono tantissimi e i più famosi sono forse quelli citati ad inizio articolo: SVN e Mercury.
Git è riuscito a farsi strada tra questi colossi grazie ad alcune caratteristiche che lo rendono unico nel suo genere e non a caso viene utilizzato da diversi progetti importanti quali il kernel linux, android, debian… oltre ovviamente allo stesso git. Ricordiamo inoltre che git è il sistema di controllo della versione che viene usato dal nostro amato Xcode.
Probabilmente l’aspetto che più differenzia git da altri sistemi di versioning è l’essere server-less non viene usato infatti nessun server centralizzato per mantenere le informazioni sul progetto (come avviene ad esempio con svn) ma ciascuna copia ne detiene una versione completa, rendendo obsoleto il concetto di working-copy tipico degli ambienti di sviluppo basati su svn.
C’è un aspetto di git, forse meno importante, ma che soddisfa la mia voglia di ordine nel filesystem ed è il fatto che git memorizza tutte le info necessarie in una cartella “.git” all’interno della root del progetto senza riempire il filesystem di cartelle .svn.
Facciamo pratica
Per comprendere git non ci servirà né Xcode né altri programmi. Ci baseremo infatti esclusivamente sul terminale. Avviamo quindi il terminale e creiamo la cartella “learn git” dove meglio ci piace. (ricordo che nel terminale cd è il comando per cambiare directory e mkdir quello per crearne una nuova).
Dall’interno della cartella appena creata digitiamo il comando
git init
Vedremo quindi un messaggio simile a questo:
Initialized empty Git repository in /Users/ignazioc/Desktop/learn git/.git/
Abbiamo appena creato il nostro primo repository. Possiamo infatti vedere che all’interno della cartella “learn git” è stata creata una cartella nascosta “.git”
$ ls -laF total 0 drwxr-xr-x 3 ignazioc staff 102 Dec 8 18:07 ./ drwx------+ 22 ignazioc staff 748 Dec 8 18:07 ../ drwxr-xr-x 10 ignazioc staff 340 Dec 8 18:07 .git/
Una volta che il repository è stato creato iniziamo ad aggiungere files al nostro progetto, aggiungiamo ad esempio un file di testo “file1.txt” che al suo interno abbia questo testo:
Questa è la prima versione del progetto.
Per farlo da terminale potete semplicemente scrivere:
echo "Questa è la prima versione del progetto" > file1.txt
Facciamo il commit del nostro primo progetto
Supponiamo che il nostro lavoro sia finito qui, siamo soddisfatti della frase scritta e vogliamo che diventi un punto fermo nella storia del nostro progetto: quello che vogliamo è creare un oggetto commit o come si dice in gergo “fare il commit del progetto”.
Un commit è composto dai file che sono stati modificati dal precedente commit, un riferimento a tale commit e da un nome univoco.
Se avete studiato un pò di teoria dei grafi potete immaginare i vari commit come un grafo aciclico e diretto:
- ciascun commit, escluso il primo, ha un riferimento ai precedenti commit (può essere figlio di due o più commit)
- ciascun commit, escluse le foglie, hanno un riferimento ai commit successivi.
Per creare il nostro primo commit digitiamo:
git add .
Questo comando dirà a git quali files aggiungere nel commit, in questo caso verranno aggiunti tutti i files modificati o aggiunti dal precedente commit.
Eseguimo quindi il commit digitando:
git commit -m "Primo commit"
Dovreste ottenere questo output:
$ git commit -m "Primo commit" [master (root-commit) 5b28669] Primo commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file1.txt
in cui si vede chiaramente che abbiamo aggiunto un file.
Creiamo altri due file sulla falsariga del primo e creiamo un nuovo commit dopo aver creato ciascun file.
Dopo aver creato tre commit digitiamo:
git log
vedremo un risultato simile al seguente:
$ git log
commit a727634e6807cbae1eb1a0e2c01e68d08ded3e1b
Author: Ignazio
Date: Thu Dec 8 18:38:14 2011 +0100
Terzo commit
commit d4faaf42fa6cd1bc8e2d045c7bc5fb4fae0ab021
Author: Ignazio
Date: Thu Dec 8 18:37:50 2011 +0100
Secondo commit
commit 5b2866927ff5477ec225259dbf502577b44e7afa
Author: Ignazio
Date: Thu Dec 8 18:34:47 2011 +0100
Primo commit
Vediamo in ordine inverso i tre oggetti commit che abbiamo creato, con tanto di nome univoco SHA1, l’autore la data ed il commento.
Altri comandi molto utili sono:
- git status: mostra quali file sono cambiati tra lo stato attuale del progetto e lo stato corrente del repository (*)
- git diff: mostra le differenze sui singoli files
- git mv: marca un file come da spostare sul repository
- git rm: marca un file come da rimuovere sul repository
(*) l’indicazione dello stato corrente necessita una spiegazione: all’interno del repository vengono mantenuti dei riferimenti ai diversi oggetti commit, il riferimento HEAD punta al commit corrente e viene portato avanti automaticamente quando si effettua un nuovo commit.
Una vita non lineare
I progetti non hanno mai una vita lineare, neanche nel mondo ideale. Ci sono sempre almeno un paio di versioni “funzionanti” nelle quali si prova ad aggiungere nuove funzionalità o rimuovere vecchi problemi. git tiene conto di queste esigenze e risponde con la funzionalità chiamata branch. In un repository possono coesistere più branch contemporaneamente, il primo viene creato di default e si chiama master tutti gli altri possono essere creati successivamente dall’utente.
Per creare un nuovo branch occorre digitare:
git branch nuovo_ramo
in questo modo abbiamo creato un nuovo ramo. Possiamo vedere il risultato di questo comando digitando
$ git branch * master nuovo_ramo
Questo però non ci porterà automaticamente a lavorare sul ramo appena creato, infatti, se proviamo a fare delle modifiche e creare un nuovo commit, vedremo che le modifiche vengono apportate al branch master.
$ echo "Questa è la quarta versione del progetto" > file4.txt
$ git add .
$ git commit -m "Quarto commit"
$ git log
commit 738018f1e5058e4c6f8f23f13960dbf8c7740976
Author: Ignazio
Date: Thu Dec 8 19:32:29 2011 +0100
Quarto commit
commit a727634e6807cbae1eb1a0e2c01e68d08ded3e1b
Author: Ignazio
Date: Thu Dec 8 18:38:14 2011 +0100
Terzo commit
commit d4faaf42fa6cd1bc8e2d045c7bc5fb4fae0ab021
Author: Ignazio
Date: Thu Dec 8 18:37:50 2011 +0100
Secondo commit
commit 5b2866927ff5477ec225259dbf502577b44e7afa
Author: Ignazio
Date: Thu Dec 8 18:34:47 2011 +0100
Primo commit
Per iniziare a sviluppare sul nuovo branch dobbiamo digitare il comando:
git checkout nuovo_ramo
Dopo aver switchato sul branch su cui vogliamo lavorare effettuiamo un nuovo commit come abbiamo fatto in precedenza:
$echo "Questa è la quinta versione del progetto" > file5.txt git add . git commit -m "Quinto commit"
Se guardiamo il log vediamo che non appare il quarto commit, perché è stato effettuato sul branch master, mentre stiamo lavorando sul branch nuovo_ramo.
commit eb9a069a7d566363fcfa772d41d50713f875c7f7
Author: Ignazio
Date: Thu Dec 8 19:41:03 2011 +0100
Quinto commit
commit a727634e6807cbae1eb1a0e2c01e68d08ded3e1b
Author: Ignazio
Date: Thu Dec 8 18:38:14 2011 +0100
Terzo commit
commit d4faaf42fa6cd1bc8e2d045c7bc5fb4fae0ab021
Author: Ignazio
Date: Thu Dec 8 18:37:50 2011 +0100
Secondo commit
commit 5b2866927ff5477ec225259dbf502577b44e7afa
Author: Ignazio
Date: Thu Dec 8 18:34:47 2011 +0100
Primo commit
Per avere una idea grafica di quello che sta succedendo possiamo usare questo comando (trovato su stackoverflow):
git log --graph --date-order -C -M --pretty=format:" %ad [%an] %Cgreen%d%Creset %s" --all --date=short
il cui output è questo:
* 2011-12-08 [Ignazio] (nuovo_ramo) Quinto commit | * 2011-12-08 [Ignazio] (HEAD, master) Quarto commit |/ * 2011-12-08 [Ignazio] Terzo commit * 2011-12-08 [Ignazio] Secondo commit * 2011-12-08 [Ignazio] Primo commit
In questa immagine, invece, vedete lo stesso output con un programma dotato di GUI:

merge
Terminate le modifiche effettuate sul branch nuovo_ramo è adesso il momento riportarle sul branch master. Purtroppo non abbiamo garanzia che nessuno abbia intanto modificato i file del branch master, anzi, in uno sviluppo condiviso, questa è la norma, quindi incrociamo le dita e speriamo che non ci siano conflitti di sorta.
Switchiamo sul branch master e digitiamo:
git merge nuovo_ramo
Ok, ci è andata bene, non ci sono stati problemi ed il merge è andato a buon fine:
Merge made by recursive. file5.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 file5.txt
Se esaminiamo i log a questo punto noteremo che è stato creato il commit di tipo merge e sono presenti sia il quarto che il quinto commit:
commit 1bfdc5768b55b80b50bff8a8c3ad28e6fd6dd699
Merge: 738018f eb9a069
Author: Ignazio Calò
Date: Thu Dec 8 22:15:42 2011 +0100
Merge branch 'nuovo_ramo'
commit eb9a069a7d566363fcfa772d41d50713f875c7f7
Author: Ignazio Calò
Date: Thu Dec 8 19:41:03 2011 +0100
Quinto commit
commit 738018f1e5058e4c6f8f23f13960dbf8c7740976
Author: Ignazio Calò
Date: Thu Dec 8 19:32:29 2011 +0100
Quarto commit
Diamo uno sguardo al grafo per capire cosa è successo:
* 2011-12-08 [Ignazio] (HEAD, master) Merge branch 'nuovo_ramo' |\ | * 2011-12-08 [Ignazio] (nuovo_ramo) Quinto commit * | 2011-12-08 [Ignazio] Quarto commit |/ * 2011-12-08 [Ignazio] Terzo commit * 2011-12-08 [Ignazio] Secondo commit * 2011-12-08 [Ignazio] Primo commit ignaziocmac:learn git ignaziocalo$

Da notare che il nuovo oggetto commit ottenuto con il merge ha due genitori, il quarto commit del brach master ed il quinto commit del branch nuovo_ramo.
Rimuovere il branch
Una volta effettuato il merge probabilmente il branch secondo_ramo non ci servirà più, possiamo quindi rimuoverlo digitando:
git branch -d nuovo_ramo
Questa prima parte della guida all’uso di git termina qui, nella prossima puntata affronteremo la condivisione dello stesso progetto su più utenti, anche attraverso internet.
Buon coding!










11 Responses to “Impariamo ad usare git (prima parte)”
10 Gennaio 2012
LucaCiao, trovo molto interessante questo tuo articolo (e anche il seguito).. volevo utilizzare questo sistema di gestione della documentazione per scopi non legati direttamente alla programmazione, ma per gestire altre forme di documenti (testi). Credi che sia fattibile? se ho un file “Primo Progetto già fatto” come faccio ad utilizzare quello come primo file da mettere nella repository??? Grazie
10 Gennaio 2012
Luca…altra domandina… qual’è l’applicazione che hai utilizzato per la visualizzazione del grafico??
10 Gennaio 2012
ignazioccerto che puoi usarlo anche per altri progetti, basta dare lo stesso comando git init e poi git add . e poi git commit -m “commento”.
l’applicazoine si chiama gitx
11 Gennaio 2012
Lucaok! Grazie mille!!!
6 Marzo 2012
MorisOttimo articolo!
4 Novembre 2012
Netdesign (Fabio Buda)Davvero un buon articolo, chiaro ed esaustivo. Vorrei soltanto ricordare una funzione utilissima di git, la possibilità di visualizzare repository via web. È molto utile sopratutto per i progetti con una lunga cronologia!
Ciao e a presto,
Fabio
7 Febbraio 2013
morpeSalve!
io non mi occupo di programmazione, sono un musicista e fonico che ha collaborazioni con altri musicisti, posso usare GIT per versionare un progetto di logic??
7 Febbraio 2013
Ignazioccerto che lo puoi usare. Purtroppo parte della forza dei sistemi di versioning sta nel merge delle modifiche..quindi l’utente A modifica il file X, l’utente B modifica lo stesso file e git è in grado di fondere le due modifiche in una nuova versione del file. Questo non è possibile con i file binari (immagini, video, suoni). Non puoi per esempio prendere una foto, l’utente A modifica il colore del cielo..l’utente B modifica il colore dei fiori…non puoi aspettarti che un programma riesca a “fondere” le due modifiche. Però per tutto il resto non c’è problema…
14 Febbraio 2013
lucaSalve a tutti.
Innanzitutto grazie per il tutorial.
Quando scrivo da terminale:
git initricevo il seguente messaggio:
-bash: git: command not foundDeve eseguire installare qualche cosa?
Grazie.
Luca
14 Febbraio 2013
ignaziocsi, devi installare git. Con le ultime versioni di xcode non viene più inserito ma si installa a parte. Dovresti cercare qualcosa che si chiama “xcode developer command line tools” mi pare che si possa scaricare direttamente anche dalla sezione “download” delle preferenze di xcode…o in alternativa dal sito apple dev.
14 Febbraio 2013
lucaGrazie, ora vedo…..