Perché Git è Meglio di X

where "x" is one of
Questo sito esiste perché ultimamente sembra che io dia l'impressione di stare molto tempo a difendere gli utilizzatori di Git da accuse di fanatismo acritico, di cavalcare l'onda di quel che sembra promettente e di voler essere creduti a prescindere dai fatti. Così, ecco qua il perché le persone stanno passando da X a Git e le motivazioni per cui dovresti farlo anche tu. Basta semplicemente cliccare su una motivazione per vederla.
hg bzr svn perforce

Branching Locale Senza Sforzi

Probabilmente la caratteristica più attraente di Git, che lo posizione davvero in una categoria a parte rispetto a praticamente ogni altro SCM esistente, è il suo modello di branching. È completamente differente rispetto a tutti gli altri modelli con cui verrà confrontato qui, molti dei quali sostengono l'idea che il branching migliore sia fondamentalmente un clone del repository in una nuova directory.
Git non funziona in tal modo. Git consente di avere parecchie branch locali che possono essere completamente indipendenti l'una dall'altra consentendo peraltro la creazione, merging e cancellazione di linee di sviluppo secondarie.
Questo vuol dire che tu puoi fare cose come:
  • Creare una branch per provare un'idea, fare qualche commit, tornare indietro al punto dal quale hai fatto il branching, applicare una patch, riprendere al punto in cui stavi facendo gli esperimenti per poi farne un merge.
  • Avere una branch che contiente sempre e solo quello che va in produzione, un'altra dentro cui fai il merge per il testing e parecchie branch più piccole per il tuo lavoro quotidiano ordinario.
  • Creare nuove branch per ciascuna singola funzionalità alla quale stai lavorando, in modo da poter alternarti senza interruzioni su ciascuna di esse, ed eliminare gradualmente ciascuna branch per la quale la funzionalità venga incorporata nella branch principale.
  • Creare una branch e sperimentarci dentro, per poi renderti conto che non funzionerà e cancellarla senza problemi, abbandonando il lavoro — senza che nessun altro neppure lo veda (anche nel caso in cui nel frattempo hai eseguito push su altre branch).
branches flowchart
Nota che quando esegui un push su un repository remoto, non ti viene richiesto di inviare tutte le tue branch. Puoi condividerne qualcuna o nessuna di esse. Questo consente di lasciare libere le persone di provare nuove idee senza la preoccupazione di dover pianificare come e quando dovranno effettuarne il merging o come condividerle con gli altri.
È possibile riuscire a fare alcune di queste cose con gli altri sistemi, ma il lavoro necessario è molto più arduo e predisposto ad errori. Git lo rende invece incredibilmente semplice e, non appena assimilato, cambia il modo di lavorare di molti sviluppatori.
jamis twitter trevorturk twitter thillerson twitter boblmartens twitter mathie twitter
svn perforce

Tutto è Locale

Ciò è fondamentalmente vero per tutti i SCM distribuiti, ma dalla mia esperienza lo è ancor di più con Git. Ci sono veramente poche occorrenze di 'fetch', 'pull', 'push' che non comunichino con qualcosa di diverso del tuo hard disk.
Ciò non soltanto rende molte delle operazioni molto più veloci di quanto non lo siano abitualmente, ma ti consente inoltre di lavorare alle tue cose offline. Anche se potrebbe non sembrare una grande cosa, vengo ogni volta meravigliato da quanto spesso io lavori offline. Essere in grado di creare branch, eseguire merge, commit e navigare la storia del progetto mentre si è in aereo o in treno è davvero produttivo.
local repo to remote repo flowchart
Anche in Mercurial, comandi comuni come 'incoming' e 'outgoing' scomodano il server, mentre invece con Git puoi fare 'fetch' da tutti i server prima di andare offline e fare confronti, eseguire un merge e loggare i dati che sono sul server ma non ancora sulle tue branch locali.
Questo vuol dire che è proprio facile avere copie non solo delle tue branch, ma anche di tutte quelle di coloro i quali stanno lavorando con te nel tuo repository senza dover creare disordine tra le tue cose.
bzr svn perforce

Git è Veloce

Git è veloce. Tutti — anche i più fedeli utenti degli altri sistemi — generalmente riconoscono a Git tale titolo. Con Git, tutte le operazioni sono eseguite localmente, concedendo un pò di vantaggio a SVN e Perforce, entrambe le quali richiedono accesso alla rete per alcune operazioni. Comunque, anche se confrontato con altri DSCMs che effettuano operazioni localmente, Git è bello veloce.
Parte di questo è possibilmente dovuto al fotto che è stato costruito per lavorare sul kernel di Linux, il che significa che ha dovuto affrontare in modo efficiente un grosso repository sin dal primo giorno. Inoltre, Git è scritto in C e riduce l'overhead dei runtime tipici dei linguaggi di più alto livello. Un altro motico per cui Git è veloce è che gli sviluppatori principali hanno fatto della velocità un obiettivo progettuale dell'applicazione.
In seguito ci sono i valori di benchmark che ho eseguito su tre copie del repository contentente il codice sorgente di Django in 3 diversi SCM: Git, Mercurial and Bazaar. Ho anche eseguito test di questa cosa in SVN, ma credimi, è più lento - praticamente puoi prendere i valori di Bazaar e aggiungere la latenza di rete....
init benchmarks add benchmarks status benchmarks diff benchmarks branching benchmarks
tag benchmarks log benchmarks large commit benchmarks small commit benchmarks
Il risultato finale è stato quello che in tutto, tranne che nell'aggiunta di nuovi file, Git è risultato il più veloce. (Anche per grandi operazioni di commit, che Hg praticamente eguagliava, ma considera che il commit provato era così grande che difficilmente sarà mai fatto in applicazioni reali qualcosa del genere - le comuni operazioni di commit sono molto più veloci in Git)
Git Hg Bzr
Init 0.024s 0.059s 0.600s
Add 8.535s 0.368s 2.381s
Status 0.451s 1.946s 14.744s
Diff 0.543s 2.189s 14.248s
Tag 0.056s 1.201s 1.892s
Log 0.711s 2.650s 9.055s
Commit (Grande) 12.480s 12.500s 23.002s
Commit (Piccolo) 0.086s 0.517s 1.139s
Branch (A freddo) 1.161s 94.681s 82.249s
Branch (A caldo) 0.070s 12.300s 39.411s
I dati di branch a freddo e a caldo sono relativi a quei test provati la prima e la seconda volta creando una branch su un repository - essendo il secondo valore una branch con una cache disco ancora "calda".
Sarebbe da notare che sebbene i dati per 'add' sono molto più lenti, questo vale per inserimenti di numerosi file - più di 2000. Per la gran parte di quello che la maggioranza delle persone fa quotidianamente, operazioni di 'add' impiegano soltanto una frazione di secondo in ciascuno di tali sistemi Tutte le altre operazioni testate qui (eccezion fatta per grandi commit, forse) sono maggiormente indicative sulle cose che potresti effettivamente fare giorno per giorno.
Questi valori non sono molto difficili da riprodurre, basta semplicemente clonare il progetto Django in ciascuno dei sistemi e provare alcuni comandi in ciascuno.
  • git clone git://github.com/brosner/django.git dj-git
  • hg clone http://hg.dpaste.com/django/trunk dj-hg
  • bzr branch lp:django dj-bzr
  • svn checkout http://code.djangoproject.com/svn/django/trunk dj-svn
svn

Git è Compatto

Git è proprio bravo a limitare l'occupazione del disco. La tua directory Git sarà (in generale) appena più larga di un checkout con SVN — in alcuni casi proprio più piccola (pare che ci finisca un bel pò di roba in quelle directory .svn).
I seguenti dati sono presi da cloni del progetto Django in ciascun dei suoi mirror Git semi-ufficiali allo stesso punto della history.
Git Hg Bzr Bzr* SVN
Repo Singolo 24M 34M 45M 89M
Intera Directory 43M 53M 64M 108M 61M
* il secondo dato Bzr è stato ottenuto dopo che ho lanciato 'bzr pack', che pansavo dovesse servire a compattarlo, ma invece è finito, per qualche ragione, col renderlo molto più grosso.
hg bzr svn perforce

L'Area di Stage

A differenza degli altri sistemi, Git ha quel che si chiama un'"area di stage" o "indice". È un'area intermedia nella quale puoi impostare come deve presentarsi quello che intendi mandare in commit prima di eseguirlo.
Il bello dell'area di stage e che posiziona Git a parte rispetto agli altri strumenti, è che in un modo semplice si possono porre in stage solo alcuni dei tuoi files man mano che li hai pronti ed effettuare il commit su di loro e non su su tutti i file modificati, o anche elencarli dalla linea di comando durante il commit.
add commit workflow diagram
Questa cosa ti consente di mettere in stage solo porzioni di un file modificato. Sono finiti i tempi in cui dovevi fare due modifiche logicamente distinte su un file prima che ti rendessi conto di esserti dimenticato di fare il commit su una delle due. Adesso puoi mettere in stage la modifica di cui hai bisogno per il commit attuale e in seguito mettere in stage le altre per il commit successivo. Questa caratteristica funziona per un qualsiasi numero di modifiche del file che ti servano.
Naturalmente, Git ti lascia ignorare le suddette caratteristiche se non hai bisogno di un tale tipo di controllo — basta spiattellare un '-a' al tuo comando di commit per aggiungere tutti i cambiamenti a tutti i file nell'area di stage.
commit only workflow diagram
svn perforce

Distribuito

Ona delle cose più forti di un SCM distribuito, incluso Git, è quello di essere distribuito. Questo significa che invece di fare un "checkout" dell'attuale punta del codice sorgente, fai un "clone" dell'intero repository.
Questo vuol dire che anche se stai usando un workflow centralizzato, ogni utente ha quel che è essenzialmente un backup del server centrale, da ciascuno del quale potrebbe essere lanciato un push per rimpiazzare il server principale nel caso di un crash o corruzione di file. Praticamente non c'è un Single Point of Failure con Git a meno che ci sia un solo punto.
E questo senza neppure rallentare l'operatività. In media, un checkout SVN è solo marginalmente più veloce di quasiasi altro DSCM. Tra i DSCM testati, Git è risultato il più veloce.
cloning benchmarks
Git 1m 59s
Hg 2m 24s
Bzr 5m 11s
SVN 1m 4s
svn perforce

Qualsiasi Workflow

Una delle cose affascinanti di Git è che grazie alla sua natura distribuita ed al suo superbo sistema di branching, si può implementare, in modo relativamente semplice, qualunque workflow immmaginabile.

Workflow in stile Subversion

Un workflow Git molto comune, specialmente per le persone che provengono da un sistema centralizzato, è, per l'appunto, un workflow centralizzato. Git non ti consentirà di eseguire un push se qualcuno ha effettuato un push dall'ultima volta che hai lanciato un fetch, in modo che il modello centralizzato in cui tutti gli sviluppatori eseguono push sullo stesso server funziona proprio bene.
subversion-style workflow

Workflow Integration Manager

Un altro workflow comune in Git è dove c'è un integration manager — una sola persona che esegue commit sul repository 'prescelto', e poi un gruppo di sviluppatori che clonano da tale repository, fanno un push verso i propri repository indipendenti e chiedono all'integrator di inserire le proprie modifiche. Questo è il modello di sviluppo che si vede spesso nell'open source o nei repository di GitHub.
integration manager workflow

Dictator and Lieutenants Workflow

Per progetti imponenti, si possono disporre gli sviluppatori in un modo simile al modo in cui ciò avviene per il kernel di Linux, dove le persone che sono responsabili di un certo sottosistema del progetto ('luogotententi') ed eseguono il merging di tutti i cambiamenti che sono pertinenti con tale sottosistema. In seguito un altro integratore di sistema (il 'dittatore') può prelevare i cambiamenti dai propri luogotenenti ed effettuare un push al repository 'prescelto' dal quale tutti clonano in seguito.
dictator and lieutenants workflow

Lo ribadisco, Git è completamente flessibile su questa cosa, per cui puoi selezionare, combinare e scegliere il workflow che ritieni adatto a te.
hg bzr svn perforce

GitHub

octocat
Potrei essere di parte qui, dal momento che lavoro per GitHub, ma aggiungo questa sezione comunque perché ci sono talmente tante persone a dire che è stato GitHub stesso il motivo specifico per cui hanno scelto Git.
Per molta gente GitHub è una ragione per usare Git perché si avvicina più ad un social network per il codice che ad un semplice sito di hosting. Le persone trovano altri sviluppatori o progetti che sono simili alle cose che stanno facendo e possono fare un fork e contribuire con facilità, creando così una community piena di energia ed entusiasmo attorno a Git ed ai progetti per cui la gente lo usa.
Ci sono altri servizi, sia per Git che per gli altri SCM, ma pochi sono orientati all'utente o hanno un obiettivo sociale e nessuno di loro si avvicina alla base di utenza. L'aspetto sociale di GitHub è l'arma vincente, e questo combinato con le funzionalità sopra elencate rendono il lavoro con Git e GitHub una grande combinazione per sviluppare rapidamente progetti open source.
Questo tipo di community non la trovi per nessun altro tipo di SCM.
puls twitter twitter
perforce

Facile da Imparare

Questo non era proprio vero — all'inizio della vita di Git, quando non era un vero e proprio SCM ma piuttosto un mucchio di strumenti che consentivano di avere un lavoro in modo distribuito. Comunque, oggi, il set di comandi e la curva di apprendimento di Git sono pressoché le stesse di un qualsiasi altro SCM, e anche meglio.
Dal momento che questo è difficile da dimostrare in modo obiettivo senza un qualche tipo di studio, mostrerò le differenze tra il menu di help predefinito per i comandi Mercurial e Git. Ho sottolineato i comandi che sono identici (o quasi) tra i due sistemi. (In Hg, se scrivi 'hg help', ti ritrovi una lista di una 40-ina di comandi).

Mercurial Help

add        add the specified files ...
annotate   show changeset informati...
clone      make a copy of an existi...
commit     commit the specified fil...
diff       diff repository (or sele...
export     dump the header and diff...
init       create a new repository ...
log        show revision history of...
merge      merge working directory ...
parents    show the parents of the ...
pull       pull changes from the sp...
push       push changes to the spec...
remove     remove the specified fil...
serve      export the repository vi...
status     show changed files in th...
update     update working directory

Git Help

add        Add file contents to the index
bisect     Find the change that introduce...
branch     List, create, or delete branches
checkout   Checkout a branch or paths to ...
clone      Clone a repository into a new ...
commit     Record changes to the repository
diff       Show changes between commits, ...
fetch      Download objects and refs from...
grep       Print lines matching a pattern
init       Create an empty git repository
log        Show commit logs
merge      Join two or more development h...
mv         Move or rename a file, a direc...
pull       Fetch from and merge with anot...
push       Update remote refs along with ...
rebase     Forward-port local commits to ...
reset      Reset current HEAD to the spec...
rm         Remove files from the working ...
show       Show various types of objects
status     Show the working tree status
tag        Create, list, delete or verify...
Prima di Git 1.6, tutti i comandi Git solevano stare nel path dei file eseguibili, cosa che risultava veramente confusionaria per le persone. Sebbene Git li riconosce ancora tutti, l'unico comando nel path è adesso 'git'. Per cui, se guardi Mercurial e Git, Git ha praticamente un set di comandi ed un sistema di help identico —al giorno d'oggi c'è veramente poca differenza mettendosi nella prospettiva dell'interfaccia utente.
Al giorno d'oggi è proprio difficile sostenere che Mercurial o Bazaar siano più semplici da imparare di Git.