[GIT] Configurazione di una repository Git

Continuiamo la trattazione sul versioning in Git, richiamando un altro post scritto sull’argomento su questo sito:

Qui viene spiegata la procedura di configurazione locale e remota di una repository Git. Servizi online di hosting molto famosi per il versionamento del vostro codice, gratuiti e a pagamento, sono GitHub, Assembla e BitBucket. Io personalmente utilizzo i primi due: su GitHub versiono i progetti “free” (visto che per renderli privati si paga), su Assembla quelli che voglio rendere privati.

git

Vi linko a tutorial per il versioning su Git, per maggiori approfondimenti:

Vediamo ora gli step per il versionamento su Git. Io uso il Terminale su MacOx, ma la procedura funziona allo stesso modo su Windows, anche se per la generazione delle chiavi SSH dovrete aiutarvi con altri programmi, come Putty.

1. Generazione delle chiavi SSH. Le chiavi SSH servono per stabilire una connessione sicura tra il vostro pc e l’account remoto della repository Git, permettendovi anche l’autenticazione. Dopo aver generato le chiavi sul vostro account remoto (GitHub, per esempio), dovrete copiare nelle Impostazioni la chiave pubblica generata.

cd ~/.ssh
# Ci si sposta nella directory ".ssh" presente sul pc. Se non c'è occorre crearla.

Si generano le chiavi, lanciando il comando ssh-keygen da terminale:

ssh-keygen -t rsa -C "your_email@example.com"
# Crea una nuova chiave SSH con il tuo indirizzo email

# Genera la coppia di chiavi rsa ssh pubblica e privata. A video uscirà un messaggio del genere:
# Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter]
# se non digiti nulla e premi invio, verrà salvata la chiave privata nel file id_rsa della cartella .ssh

Il terminale chiederà anche la passphrase, ossia la password:

Enter passphrase (empty for no passphrase): [Type a passphrase]
# Enter same passphrase again: [Type passphrase again]

Il comando genererà la coppia di chiavi pubblica e privata.

Your identification has been saved in /Users/you/.ssh/id_rsa.
# Your public key has been saved in /Users/you/.ssh/id_rsa.pub.
# The key fingerprint is:
# 01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com

A questo punto, digitate il seguente comando per copiare la chiave pubblica, da incollare poi nelle Impostazioni dell’account della vostra repo Git (per esempio, su GitHub, vi è la sezione “Add SSH keys” delle Impostazioni Account):

pbcopy < ~/.ssh/id_rsa.pub
# Copia il contenuto del file id_rsa.pub negli Appunti

Eccovi un riferimento utile per questo step: Generating SSH Keys

2. Installazione di Git. Se non già presente, dovete installare Git sul vostro pc (per capire se è già preinstallato, basta lanciare il comando git sul terminale e vedere se vi elenca i vari comandi previsti dal protocollo). L’installazione è molto semplice: basta scaricare l’ultima release da questo link (Git). Altro riferimento utile per questo step: Set Up Git

3. Creazione di una repository. La prima cosa da fare è creare una repository sull’account remoto (di GitHub o Assembla, per esempio). Lì salverete il contenuto del vostro progetto, sincronizzandolo di volta in volta dai vostri pc. Riferimento: Create a repo.

Adesso passiamo alla configurazione della repo GIT locale alle vostre macchine. Spostatevi con il terminale in corrispondenza della directory root del vostro progetto oppure create una directory di progetto da zero. Per esempio:

mkdir ~/Hello-World
# creo una directory di progetto "Hello-World" nella cartella Users

cd ~/Hello-World
# mi sposto in corrispondenza della cartella di progetto appena creata

git init
# inizializzo la cartella di progetto come repository GIT. 
# Ecco il messaggio che vi verrà visualizzato:

# Initialized empty Git repository in /Users/you/Hello-World/.git/

# creo un file README, in cui inserire le informazioni sul progetto
touch README

# committo il file README creato
git add README
# il comando ADD mette il file README nell'area "stage", ossia non è ancora commitato

git commit -m 'first commit'
# committo le modifiche della repository, lasciando il messaggio "first commit"

Se avete inserito (o erano già presenti) altri file/directory nella directory di root (oltre README), allora dovete aggiungerli tutti nell’area “stage”, prima di committarli, con il comando ADD:

# aggiungo tutti i file all'area "stage"
# dopo l'add metto il punto (.)
git add .

git commit -m 'new commit'

Infine, per salvare il tutto sulla repo remota, ecco i comandi:

git remote add origin https://github.com/username/Hello-World.git
# creo una "origin" remota sulla repository GitHub

git push origin master
# mando i commit al branch "master" su GitHub

[GIT] Il versionamento distribuito con GIT ed un efficiente modello di branching

Vi scrivo oggi di un interessante modello di versionamento che si basa sul famosissimo GIT, repo usata ai primordi per la distribuzione del kernel Linux e negli ultimi tempi come maturo e completo sistema di versioning distribuito. GIT ha attirato gran parte degli sviluppatori di vari linguaggi, tanto da diventare più utilizzato di SVN.

Per la configurazione di GIT e alcune nozioni di base, vi rimando all’ottimo articolo “CVS, SVN e GIT!“.
Per approfondire, il miglior riferimento è il freebook online: http://git-scm.com/book
Carina è anche la semplice guida “git – the simple guide
Personalmente uso il servizio online di GITHUB per versionare i miei progetti. Anche se mi sto trovando molto bene con Assembla, invece, per versionare piccoli progetti su repo SVN. Ho utilizzato Mercurial, ma ho avuto non pochi problemi di compatibilità/bug con vari plugin HG. Se volete versionare su una repo GIT, vi consiglio di installare i client SmartGIT, SourceTree o Tortoise (su Mac, ma alcuni anche per Windows). Su XCode in Mac, il plugin di GIT è già configurato e potete sceglierlo come versionatore del vostro progetto.
Ora, qual è il punto di forza di GIT? Sicuramente la decentralizzazione del codice sorgente. Nell’articolo che vi linko, si enumerano i punti a favore di GIT rispetto a sistemi centralizzati di controllo versione come SubversionWhy you should switch from SubVersione to GIT
In sintesi, come già detto, GIT ha il vantaggio di essere una repo distribuita. Invece di lanciare il comando “svn checkout (url)“, che preleva l’ultima versione della repository di progetto, su GIT si lancia il comando “git clone (url)”  che copia-clona l’intera history di progetto. Ciò significa che il clone non intacca il progetto originale presente sulla repo e uno sviluppatore può autonomamente lavorare su una sua copia, in modalità offline.
Con questo nuovo paradigma è possibile committare in una repository locale anche in assenza di connessione alla rete, cosa che invece non era possibile con SVN, visto che il committ viene fatto interamente sulla repo remota.
Altro vantaggio implicito di questo modello è che il workflow non ha un “single point of failure“. In GIT ciascun membro può pushare su qualsiasi altro server se quello centrale viene corrotto, così che altri membri possono accedere in SSH e ripristinare la working copy in pochi minuti.
Grazie al meccanismo di pull e push, la sincronizzazione tra le repo GIT di ciascun membro è alquanto efficiente. Il meccanismo distribuito permette di creare tante repo private (locali) e sincronizzarle con quelle pubbliche. Un integration manager può pullare tutte le copie pubbliche su un unico “gold repository”, dove ci sarà la versione stabile da deployare in produzione.

 

Una feature ben fatta di GIT è quella che permette il merging tra i branch. Ogni membro del team può creare la propria “feature” su un branch separato e committare/pullare il tutto sul branch condiviso (modello che approfondiremo in seguito).
Quando viene creato un branch in GIT, si può facilmente switchare a quello nuovo per iniziare a svilupparci sopra. I branch si possono riaprire per fixare bug, inserire nuovo codice e poi mergiare il tutto sulla “mainline work“. L’operazione di merge genera pochissimi conflitti sui file.
Esiste una vera e propria “area di sosta” dei file, detta staging area, che non è altro che una cache locale in cui si trovano le modifiche del codice prima del commit. Questa è molto utile per avere una peer-review del lavoro fatto. E’ possibile committare i singoli changeset in seguito. GIT mantiene traccia di “parti di file” (stage files) come delta delle modifiche apportate al codice, che si possono committare selettivamente (patch staging).
Queste modifiche, logicamente separate, possono essere committate separatamente per una facile review del progetto e tale feature è detta cherry-pickable.
Passiamo ora alla descrizione di un efficiente modello di branch di GIT, prendendo come riferimento l’articolo “A successful GIT branching model“.

 

In questo modello esiste una repo denominata “origin” che è quella centrale in cui tutti i membri del team pullano e pushano una versione stabile o condivisa delle modifiche.

 

 

Main branches. La repo centrale contiene due main branches che vivono per tutta la durata del progetto e che si chiamano “master” e “develop“.

 

Il branch origin/master conterrà il codice che verrà messo in produzione. Il branch origin/develop è quello dove vengono pushate tutte le modifiche di sviluppo di ciascun membro del team di sviluppo e che viene continuamente aggiornato fino a quando non si è prodotta una versione stabile da mettere in produzione. È anche detto “branch di integrazione” delle repo distribuite tra i vari sviluppatori.
Quando si reputa stabile, il codice su origin/develop viene mergiato su origin/master.
Supporting branches.
Oltre ai branch “principali”, esistono altre tipologie di branch di vita limitata (detti branch di supporto) che si classificano come segue:
  • Feature branches
  • Release branches
  • Hotfix branches

Feature branches. Si stacca (branch off) da develop e si mergia sempre in esso. Si può chiamare in qualsiasi modo tranne che master, develop, release-* o hotfix-*.
Si chiama anche “topic branches” e contiene gli sviluppi di una features o funzionalità logica del progetto.
Per creare un nuovo feature branch facendo il branch off da develop:
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
 Per mergiare la feature su develop quando è stata ultimata:
$ git checkout develop
#Switched to branch 'develop'
$ git merge --no-ff myfeature
#Updating ea1b82a..05e9557
#(Summary of changes)
$ git branch -d myfeature
#Deleted branch myfeature (was 05e9557).
$ git push origin develop
Il flag –no-ff (dove “ff” sta per “fast-forward”) evita di “confondere” il codice della features nella mainline di progetto. Molto utile nel caso si voglia ricostruire la storia dei commit.

 

Release branches. Il branch off qui avviene da develop e si può mergiare sia su master che su develop. La naming convention è release-*. Questo tipo di branch supporta la preparazione per un nuovo rilascio in produzione. Infatti, mette a disposizione un insieme di metatag utili per etichettare la build version, la data di rilascio, ecc.
Per creare un release branch da develop, supponendo di stare alla versione 1.1.5 in produzione e di voler passare alla 1.2:
$ git checkout -b release-1.2 develop
#Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
#Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
#[release-1.2 74d9424] Bumped version number to 1.2
#1 files changed, 1 insertions(+), 1 deletions(-)
 A questo punto, possiamo mergiare il release branch sul master:
$ git checkout master
#Switched to branch 'master'
$ git merge --no-ff release-1.2
#Merge made by recursive.
#(Summary of changes)
$ git tag -a 1.2
Per prendere le modifiche fatte nel release branch e portarle in develop:
$ git checkout develop
#Switched to branch 'develop'
$ git merge --no-ff release-1.2
#Merge made by recursive.
#(Summary of changes)
Infine, per rimuovere il release branch:
$ git branch -d release-1.2
#Deleted branch release-1.2 (was ff452fe).

 

Hotfix branches. Il branch off si fa da master e si mergia sia in master che in develop. Il naming convention è hotfix-*.
È come il release branch ma viene creato dopo che si ha uno stato indesiderato in produzione, come un bug critico da risolvere immediatamente. A tal scopo di fa un branch off dal corrispondente tag del master che marca la versione in produzione.

Supponendo di avere in produzione la versione 1.2 su cui è avvenuto un severe bug, un hotfix branch si crea così:

 

$ git checkout -b hotfix-1.2.1 master
#Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
#Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
#[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
#1 files changed, 1 insertions(+), 1 deletions(-)
 I commit delle modifiche per la correzione del bug si effettuano su tale hotfix:
$ git commit -m "Fixed severe production problem"
#[hotfix-1.2.1 abbe5d6] Fixed severe production problem
#5 files changed, 32 insertions(+), 17 deletions(-)
A fine correzione, il merge sul master si fa come un release branch:
$ git checkout master
#Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
#Merge made by recursive.
#(Summary of changes)
$ git tag -a 1.2.1
E per allineare il develop con il bugfix:
$ git checkout develop
#Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
#Merge made by recursive.
#(Summary of changes)
Unica eccezione si ha quando la fix riguarda un release branch esistente. In tal caso, l’hotfix va mergiato su tale release, invece che su develop.
Per rimuovere l’ hotfix branch:
$ git branch -d hotfix-1.2.1
#Deleted branch hotfix-1.2.1 (was abbe5d6).

[Subversion] Spostamento di una repository da un server SVN ad un altro

In un precedente articolo si è parlato della installazione e configurazione di un server SVN su ambiente Linux (distribuzione Debian). Una  volta configurato il server, però, mi si è posto il problema dell’importazione di una repository salvata su un server SVN installato su un’altra macchina (Windows), eseguendo una procedura alquanto semplice e che ha “travasato” tutta la history, senza perdere nessun dato.

Ecco i passi da eseguire:

1. Backup della vecchia repository: Occorre effettuare un dump della repository che si occorre importare eseguendo il comando da terminale (DOS su Windows; shell/bash su Unix)

svnadmin dump /path/to/repository > repo_name.svn_dump
									

Tale comando invoca il servizio svnadmin (occorre ovviamente essere amministratori della macchina) che esegue il comando dump, seguito dal path assoluto della repository (il path è quello del file system e non la URL della repository). Il dump copia tutta la repository in un file che ha estensione svn_dump che potete chiamare come preferite (potete specificare anche un path assoluto in cui salvare tale file).

2. Creazione della nuova repository: se non avete già creato una repository sul nuovo server SVN, occorre crearla con il comando svnadmin create

svnadmin create /path/to/repository
									

3. Importazione del dump sulla nuova repository: a questo punto, copiare il dump che avete esportato sulla nuova macchina, posizionatevi da terminale nella directory dove avete copiato il file di dump e lanciate il comando svnadmin load

svnadmin load /path/to/repository < repo_name.svn_dump
									

In alcuni casi, occorre forzare che l’UUID della nuova repository sia uguale a quella della vecchia. Per cui, se vi viene visualizzato un errore del genere dopo aver lanciato il comando load, potete rilanciare la precedente riga di codice specificando l’opzione –force-uuid (l’UUID della vecchia repository la potete vedere con un client SVN visionando le proprietà della working copy).

Ecco dei comandi utili per poter visualizzare e settare la UUID di una repository:

$ svnlook uuid /var/svn/repos cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec 
$ svnadmin setuuid /var/svn/repos  #NOTA. generate a new UUID 
$ svnlook uuid /var/svn/repos 3c3c38fe-acc0-11dc-acbc-1b37ff1c8e7c 
$ svnadmin setuuid /var/svn/repos  cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec #NOTA. restore the old UUID 
$ svnlook uuid /var/svn/repos cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec
									

Importazione di una repository a partire da una specifica revisione

E’ possibile importare una vecchia repository anche a partire da una specifica revisione. Occorre effettuare il dump specificando quale revisione importare e importando poi in modo incrementale. Ecco i comandi:

svnadmin dump --incremental -r 1234 /path/to/repository > rev1234.svn_dump

L'importazione nella nuova repository si importa allo stesso modo:
svnadmin load /path/to/repository < rev1234.svn_dump
									

 

[SubVersion] Installazione e configurazione di un server SVN su Linux Debian

In questo articolo si descrivono i passaggi per installare e configurare un server SVN (http://subversion.tigris.org/) su ambiente Linux (Debian) per il versioning del codice sorgente e della documentazione di un progetto.

Per installare l’ultima versione di Subversion presente sulla repository della distribuzione Debian, occorre lanciare da terminale il seguente comando:

$ apt-get install subversion
									

Tale comando scarica l’ultima release di Subversion e risolve tutte le dipendenze. Se si riscontrano problemi, occorre scaricare e installare tutti i pacchetti e procedere con una installazione manuale. Se si usa una distribuzione Linux che non sia Debian o il comando apt-get non è disponibile, leggete l’articolo How to install subversion on Linux and make it working.

Per verificare che l’installazione del server SVN sia andata a buon fine, basta digitare sulla shell il comando svn. Se è tutto ok, potete passare alla creazione della repository. Ecco il comando:

$ svnadmin create /srv/svn/repos
									

Tale comando crea la repository nel percorso /srv/svn/repos/ del vostro server (potete sceglierne anche uno a vostro piacimento). Se tutto è andato a buon fine, ritroverete in tale directory i seguenti file e sottodirectory:

conf/   dav/    db/    format/    hooks/    locks/     README.txt

Di seguito, ulteriori dettagli sulla configurazione e l’utilizzo del server SVN installato.

Continua la lettura