Perché amare darcs e perché odiarlo

darcs logoI DVCS sono un’idea relativamente recente, ma hanno una storia già abbastanza ricca.
In principio fu arch,
che sebbene abbia il merito di aver introdotto
il concetto di sistema di revisione distribuito, era affetto da
numerosi difetti sia di usabilità che di design (arch usava un sistema
di denominazione dei file praticamente incompatibile con windows) ed è
ormai un progetto abbandonato.

La seconda e terza generazione di questi sistemi comprende invece sia progetti di successo come git o mercurial
che sistemi meno diffusi come monotone, codeville o SVK, ognuno dei quali con diversi pregi e difetti.

In questo gruppo è presente anche darcs, che è stato uno dei primi sistemi distribuiti
ad aver avuto ampia diffusione, ma ha perso gran parte della sua visibilità quando hanno cominciato a
diffondersi git e mercurial.

La prossima uscita di darcs2 però potrebbe portare nuovo splendore a questo sistema, attaccando i difetti che
ne hanno limitato la diffusione fino ad ora.


Not Yet Another DVCS

L’idea innovativa di darcs è l’introduzione di una teoria delle patch, ovvero di una descrizione formale di cosa significa “patch” e di come siano descrivibili le relazioni tra di esse.
Il concetto è che se si riesce a sviluppare un’algebra per le patch, allora è possibile trovare dei teoremi
che permettano di migliorare gli algoritmi di merge e si ha la garanzia che le operazioni che si fanno siano
corrette, in quanto esiste una prova formale, e non perché empiricamente sembrano funzionare finché un caso
particolare non manda in malora il repository.
Ovviamente, per l’uso del sistema non è necessario comprendere questa teoria, esattamente come non bisogna
conoscere la fisica quantistica per accendere una lampadina.

Il vantaggio pratico della teoria delle patch è che è possibile
gestire in modo estremamente granulare i cambiamenti. Immaginiamo il
seguente scenario:

  • Alice crea la patch A1 e la patch indipendente AA
  • Alice crea A2, che dipende da A1, e A3 che dipende da A2
  • Bob crea la patch B1 e di seguito B2, che dipende da B1
  • Carl copia il repository di Bob e aggiunge la patch C1, indipendente

Se B1 è equivalente ad A1 (ad esempio, tutte e due correggono Incementa in Incrementa)
allora
Alice può tranquillamente copiare le patch B2 e C1 da Carl, e può in
qualunque momento rimuovere la patch AA visto che non c’è niente che
dipende da essa. Allo stesso modo, Bob e Carl possono importare le
patch A2 e A3, e possono decidere se importare AA (che è indipendente)
o A1 (rimpiazzando B1).

Il sistema garantisce anche che né Bob né Carl possano usare A3 se i requisiti sono violati (ovvero, se non
c’è A2 e almeno una delle patch che forniscono la base su cui applicarla, ovvero A1 e B1).

Questo meccanismo permette di avere un eccellente metodo di cherry picking, ovvero la possibilità di selezionare quali patch vogliamo, in modo molto preciso e immune da errori.

Vediamo un breve esempio, iniziando con il creare il repository e aggiungendo un paio di patch. I comandi
dovrebbero essere abbastanza ovvi da non necessitare di spiegazioni.

rff@ut:~/st$ mkdir repo
rff@ut:~/st$ cd repo
rff@ut:~/st/repo$ cat >> t.txt
prima linea
seconda linea
# inizializziamo il repository
rff@ut:~/st/repo$ darcs init
rff@ut:~/st/repo$ darcs add t.txt
rff@ut:~/st/repo$ darcs record
Darcs needs to know what name (conventionally an email address) to use as the
patch author, e.g. 'Fred Bloggs <fred@bloggs.invalid>'. If you provide one
now it will be stored in the file 'darcs/prefs/author' and used as a default
in the future. To change your preferred author address, simply delete or edit
this file.

What is your email address? foo@mail.com
addfile ./t.txt
Shall I record this change? (1/?) [ynWsfvpxdaqjkc], or ? for help: y
hunk ./t.txt 1
+prima linea
+seconda linea
Shall I record this change? (2/?) [ynWsfvpxdaqjkc], or ? for help: y
What is the patch name? initial import
Do you want to add a long comment? [yn]n
Finished recording patch 'initial import'

Come vedete, non è particolarmente diverso da qualsiasi altro sistema.
È interessante notare che il meccanismo di scelta dei cambiamenti presente nel comando record
permette di selezionare i cambiamenti da includere nella patch a livello di ogni file e di ogni cambiamento
nel file ed è stato considerato abbastanza valido da essere presente in mercurial 0.9.5.

Per copiare un repository si usa il comando get:

rff@ut:~/st$ darcs get repo new
Finished getting.

Aggiungiamo ora delle patch:

rff@ut:~/st/repo$ cat >> t.txt 
terza linea
rff@ut:~/st/repo$ darcs record
hunk ./t.txt 3
+terza linea
Shall I record this change? (1/?) [ynWsfvpxdaqjkc], or ? for help: y
What is the patch name? terza linea
Do you want to add a long comment? [yn]n
Finished recording patch 'terza linea'
rff@ut:~/st/repo$ cat >> t.txt
quarta linea
rff@ut:~/st/repo$ darcs record
hunk ./t.txt 4
+quarta linea
Shall I record this change? (1/?) [ynWsfvpxdaqjkc], or ? for help: y
What is the patch name? quarta linea
Do you want to add a long comment? [yn]n
Finished recording patch 'quarta linea'

E dal secondo repository importiamole tramite il comando pull

rff@ut:~/st/new$ darcs pull
Pulling from "/home/rff/st/repo"...
Sat Jan 26 16:22:41 CET 2008 foo@mail.com
* terza linea
Shall I pull this patch? (1/2) [ynWsfvpxdaqjk], or ? for help:

Come vedete, già a questo punto darcs offre un’ottima interfaccia per il cherry picking: è possibile non solo
visualizzare quante e quali patch siano presenti, ma l’interfaccia da riga di comando ci offre una quantità
di opzioni, tra cui la possibilità di visualizzare la patch, saltarla, o quant’altro.
Il sistema è abbastanza intelligente da effettuare in automatico lo skip di tutte le patch che dipendono da
una rifiutata, e mostrarci solo quelle applicabili.
In questo caso la seconda patch dipende dalla prima (il concetto “dopo la linea 3” non ha senso se il
file ha solo due linee)

rff@ut:~/st/new$ darcs pull
Pulling from "/home/rff/st/repo"...
Sat Jan 26 16:22:41 CET 2008 foo@mail.com
* terza linea
Shall I pull this patch? (1/2) [ynWsfvpxdaqjk], or ? for help: n
Skipped 1 patch due to dependencies.
You don't want to pull any patches, and that's fine with me!

D’altronde, la patch che introduce la terza linea è indipendente, per cui possiamo decidere di importare
solo quella:

Sat Jan 26 16:22:41 CET 2008  foo@mail.com
* terza linea
Shall I pull this patch? (1/2) [ynWsfvpxdaqjk], or ? for help: y
Sat Jan 26 16:23:01 CET 2008 foo@mail.com
* quarta linea
Shall I pull this patch? (2/2) [ynWsfvpxdaqjk], or ? for help: n
Finished pulling and applying.

Ovviamente, in ogni momento ci rimane l’opzione di recuperare le patch in sospeso.

Il meccanismo di cherry picking si estende a tutte le operazioni
possibili in darcs, per cui quando vogliamo inviare dei cambiamenti in
un repository remoto ci si presentano le stesse opzioni, così come
quando vogliamo inviare le patch via email a qualcuno, o applicare dei
cambiamenti ricevuti.

Un repository darcs rappresenta quindi un albero di patch che possono dipendere o meno le une dalle altre,
e non una singola linea temporale, il che permette di intervenire in qualsiasi momento su uno dei rami
aggiungendo, rimuovendo o sostituendo patch, un meccanismo che permette di seguire in modo ideale
uno sviluppo distribuito.

Validazione delle patch e dei pacchetti da distribuire

darcs si occupa di gestire il codice e va integrato con strumenti esterni per issue tracking, continuous
build/integration eccetera, però è interessante notare come sia possibile integrare nell’uso di questo
strumento un semplice meccanismo di validazione delle patch.
In sostanza, è possibile definire un comando custom per l’esecuzione dei test, che verrà eseguito nel momento
in cui registriamo una patch.
Per mostrare il meccanismo consideriamo bacon, una piccola libreria
per il BDD in ruby.

Nel repository darcs di bacon la preferenza “test” è associata al comando rake test,
che appunto esegue i test della libreria. Cambiamo il valore base di un contatore e proviamo a registrare:

rff@ut:~/bacon$ vim lib/bacon.rb  # cambiamo i valori base da 0 a 1
rff@ut:~/bacon$ darcs record
hunk ./lib/bacon.rb 13
- Counter = Hash.new(0)
+ Counter = Hash.new(1)
Shall I record this change? (1/?) [ynWsfvpxdaqjkc], or ? for help: y
What is the patch name? change base counter
Do you want to add a long comment? [yn]n
Running test...

(in /tmp/testing)
/usr/bin/ruby1.8 bin/bacon -Ilib —automatic —quiet
./lib/bacon.rb:283:in `satisfy': save some characters by typing should (Bacon::Error)
from ./lib/bacon.rb:267:in `be'
from ./lib/bacon.rb:229:in `should'
from ./lib/bacon.rb:134:in `should'
from ./test/spec_should.rb:11
from ./lib/bacon.rb:113:in `instance_eval'
from ./lib/bacon.rb:113:in `initialize'
from ./lib/bacon.rb:56:in `handle_specification'
from ./lib/bacon.rb:113:in `initialize'
from ./lib/bacon.rb:235:in `new'
from ./lib/bacon.rb:235:in `describe'
from ./test/spec_should.rb:5
from bin/bacon:108:in `load'
from bin/bacon:108
from bin/bacon:107:in `each'
from bin/bacon:107
rake aborted!
Command failed with status (1): [/usr/bin/ruby1.8 bin/bacon -Ilib —automat...]
/tmp/testing/Rakefile:72
(See full trace by running task with —trace)
Test failed!
darcs failed: exit: ExitFailure 1
Failed to record patch 'change base counter'

Abbiamo introdotto un errore e la test suite l’ha rilevato facendo fallire il comando rake test,
quindi la patch non è stata registrata. Ciò garantisce che questa disattenzione non possa propagarsi ad altri repository, in quanto ogni patch inviabile
deve aver superato i test con successo.

Il sistema è intelligente ed esegue i test sulla versione del repository registrata, non sul codice attuale,
quindi se rimangono dei bug ma non nella patch, essa verrà registrata correttamente:

rff@ut:~/bacon$ darcs rec
hunk ./lib/bacon.rb 11
- VERSION = "0.9"
+ VERSION = "0.9.1"
Shall I record this change? (1/?) [ynWsfvpxdaqjkc], or ? for help: y
hunk ./lib/bacon.rb 13
- Counter = Hash.new(0)
+ Counter = Hash.new(1)
Shall I record this change? (2/?) [ynWsfvpxdaqjkc], or ? for help: n
What is the patch name? increase version number
Do you want to add a long comment? [yn]n
Running test...

(in /tmp/testing)
/usr/bin/ruby1.8 bin/bacon -Ilib —automatic —quiet
.......................................

39 tests, 304 assertions, 0 failures, 0 errors
Test ran successfully.

Finished recording patch 'increase version number'

Notate che abbiamo registrato la patch che aumenta il numero di versione, ma non quella che cambia il valore
del contatore, e quindi i test sono stati eseguiti correttamente.

È comunque possibile che una patch introduca un errore ma non sia rilevata localmente:
immaginiamo che Alice aggiunga diverse patch, di cui una che introduca un riferimento locale
(es: FOO='/opt/foo'), che quindi farà fallire i test su altre macchine.
Quando Bob effettuerà un pull dei cambiamenti si troverà con un errore ma senza sapere di preciso
cosa l’ha provocato.

Fortunatamente, questo tipo di situazione può essere gestita facilmente grazie al comando trackdown.
Questo comando non fa altro che rimuovere le patch una a una ed eseguire i test, fino a individuare l’ultima
versione del repository che funziona correttamente e di conseguenza la patch che ha introdotto il bug.

Chiaramente, è possibile specificare un comando di test più selettivo di quello generale del repository,
per cui un bug nella funzionalità X potrà essere ricercato eseguendo solo i test relativi a X,
e non quelli dell’intero progetto.

Ne voglio uno!

darcs permette di pubblicare repository dumb, ovvero di usare semplici cartelle http o ftp pubbliche,
così come repository smart, accessibili via ssh. Nessun problema di setup e nessun bisogno di conoscere un
altro programma (cough, svnadmin, cough).

Il sistema funziona discretamente su linux/*bsd, osx e win32, e ci sono pacchetti compilati per tutti gli ambienti.
Inoltre, a differenza di SVN/CVS, tutte le informazioni vengono mantenute in una sola cartella _darcs nella root del progetto, minimizzando i problemi di gestione.

darcs si comporta correttamente quando è usato insieme ad altri VCS, ignorando i file di mercurial,
SVN o git, per cui è possibile mantenere in un proprio repository darcs locale un progetto importato da
subversion e sincronizzare i due VCS indipendentemente.

La curva di apprendimento è ridicolmente piatta e i comandi visti qui sopra sono già sufficienti per
un progetto personale.
Ma allora perché darcs non è più diffuso?

Effettivamente, questo VCS aveva avuto un discreto successo nell’era
pre-git/mercurial, per i motivi descritti qui sopra, ma da quando
questi sono diventati più maturi darcs ha perso molto momento.

Il motivo, come spesso succede nell’informatica, è poco filosofico
ma molto importante: l’efficienza.
Infatti, un’implementazione “subottimale” del sistema faceva sì che in
alcuni casi il tempo necessario a darcs per capire come gestire patch
in conflitto fosse esponenziale.

È ovvio che mentre questo può essere accettabile per piccoli repository, nel caso di progetti molto grandi
poteva essere drammatico. Io stesso mi sono trovato di fronte a operazioni di merge che hanno richiesto ore,
pur non lavorando su codebase delle dimensioni di mozilla o di linux.

git e mercurial, d’altro canto, sono stati pensati fin dall’inizio per essere efficienti con basi di codice
enormi, il che li ha resi molto più appetibili in queste situazioni e, indirettamente, in tutte le altre.

I problemi più importanti erano però relativi alla corruzione di un repository, ovvero, la perdita dei dati (i file) o dei metadati (le informazioni relative alle patch). La gravità del problema è ridotta dalla natura
distribuita di darcs, per cui ripristinare il repository principale significa semplicemente copiarlo da
un altro, ma è evidente che questo problema semplicemente non dovrebbe porsi.
Personalmente, non ho mai avuto questo problema, e anche se critiche su questo punto appaiono regolarmente su
ogni pagina web in cui si parla di darcs, credo sia interessante che il bug tracker di darcs riporta 24 casi
contenenti il termine “corruption”, tutti risolti. Per contro, quello di mercurial ne riporta 14,
una differenza non abissale.

darcs2 to the rescue

Fortunatamente, gli sviluppatori non sono stati con le mani in mano
e a breve dovrebbe uscire la versione definitiva di darcs2, che risolve
alla radice questi problemi.
Il comportamento nei merge è adesso sempre lineare e i problemi di
corruzione sembrano eliminati definitivamente.

Inoltre, darcs2 usa un formato differente per memorizzare il contenuto dei
repository, grossomodo un passaggio da una lista collegata a un dizionario/hash,
che implica differenti vantaggi:

  • non c’è bisogno di locking (ogni patch è salvata in un file univoco, non c’è overlap)
  • non è necessario leggere l’intero repository per ottenere una patch, il che rende più efficiente la copia
  • è possibile effettuare caching delle patch, il che rende più veloci operazioni su diversi repository locali

Infine, è stato recentemente aggiunto il supporto al pipelining HTTP, ovvero usare una singola connessione
HTTP per scaricare N file, invece che N connessioni, il che dovrebbe rendere molto più veloci le operazioni.

È interessante notare come i miglioramenti in darcs2 siano dovuti a due pratiche di sviluppo che sono
in un certo senso opposte, ovvero il functional testing e l’analisi formale.

Per la prima, non si tratta di nulla di rivoluzionario, semplicemente darcs possiede una ampia test suite che
comprende i precedenti problem report, per cui c’è una garanzia che i miglioramenti effettuati siano reali,
e non ipotetici. Semplice, ma non banale.

La seconda è invece una cosa più particolare: darcs è scritto in Haskell e la versione 2 fa un uso
estensivo dei cosidetti type witness: in pratica usa
definizioni di tipo di alto livello per verificare staticamente delle garanzie sul comportamento del sistema
a runtime.
Ad esempio, può essere garantito in fase di compilazione che ogni patch o sequenza di
patch sia sempre invertibile, il che significa poter effettuare in qualsiasi momento l’operazione di
revert che annulla un merge (operazione ovvia se le patch sono sempre ordinate, come in subversion,
ma molto più complessa in una struttura non-lineare come quella di darcs).

Oppure, si può avere la garanzia formale che due sequenze di patch equivalenti (ad esempio, l’aggiunta di
una linea e poi di un altra) siano considerate tali solo se lo stato iniziale e quello finale sono
uguali.

Conclusioni

La scelta di quale VCS usare è dipendente da una serie di fattori, sia tecnici che sociali e va fatta caso
per caso. In linea generale, io preferisco darcs ad altri VCS perché ognuno di essi ha qualcosa che non mi
soddisfa:

  • CVS è il VCS di Satana
  • SVN non è distribuito
  • monotone usa un database dei metadati basato su un database invece che su file multipli
  • git soffre di seri problemi di usabilità e supporta windows in modo scadente
  • mercurial.. ok, è accettabile, ma ritengo superiore il cherry picking di darcs

D’altronde, rispetto a ognuno di questi, darcs ha degli svantaggi:

  • SVN è diffusissimo e spesso rappresenta la scelta più semplice
  • monotone fa un uso estensivo di certificati crittografici
  • git è molto più veloce di darcs (versione 1)
  • mercurial è molto più veloce di darcs (versione 1) e facilmente estensibile
  • non ci sono vantaggi a usare CVS, mi spiace

La versione 2 di darcs ha il potenziale di risolvere gli unici problemi davvero grossi di questo sistema,
e sarà interessante vedere quanto manterrà le promesse. Nel frattempo, io consiglio di sperimentare la
versione attuale in progetti personali, il manuale è ben scritto e
come già detto la curva di apprendimento è straordinariamente piatta.
Anche se non userete mai questo VCS per lavoro, imparare qualcosa di nuovo è sempre positivo.

Comments

  1. Bello 🙂 Considerando tutti i modi più o meno bizantini in cui sono riuscito ad incasinare vari repository SVN, probabilmente darò uno sguardo a questo arch prima di creare il prossimo VC privato.

    Su SourceForge comunque continuerò ad usare SVN.

  2. Alan Franzoni says:

    Putroppo il problema attuale più grosso è l’enorme moltiplicazione dei sistemi di controllo versione distribuiti. Bazaar, git, mercurial, darcs, monotone… ognuno di essi richiede un minimo di pratica, i tool di conversione esistono ma non sono perfetti, ed ognuno di essi richiede un plugin specifico per ogni strumento di sviluppo che si va ad utilizzare. Svn ormai avrà anche il suo tempo, ma (come cvs) aveva di fatto stabilito uno standard.

    Inoltre molti sistemi, in fase di sviluppo, si sono “rubati” le feature a vicenda, tant’è che fino ad un annetto fa le differenze tra bzr e hg erano tangibili, oggi sono così minimali che si potrebbe benissimo usare un tool unico con qualche opzione di configurazione.

    Il rischio di tutta questa frammentazione è che alla fine resteremo tutto con svn per la mancanza di uno standard alternativo, o (peggio) andremo ad utilizzare un sistema subottimale soltanto perché è più diffuso o più supportato, magari soltanto per la sponsorizzazione di una qualche grande azienda.

  3. Lorenzo Bolognini says:

    Grazie Gabriele, è una bella introduzione.

    Come vedi il supporto per il cherry picking in SVN 1.5? Sarà ai livelli di darcs?

    Io cmq continuo a non capire quali vantaggi (e in quali scenari) offrano i sistemi distribuiti.

  4. Alan: da una parte sono d’accordo, c’è un certo vantaggio nella standardizzazione de facto di uno strumento, ma dall’altra vedo i vantaggi della concorrenza.

    git ad esempio ha un sistema di record che traccia in automatico i cambiamenti, mentre tutti gli altri usano metadati espliciti.
    É una buona idea?
    Se si gli altri copieranno e si andrà avanti, se non ci fosse stato un approccio alternativo ci sarebbe stato meno progresso.

    D’altronde, nell’ottica del contribuire a un progetto esistente, io ho sempre trovato molto più complesso ottenere confidenza con la codebase che con i tool connessi.

  5. Lorenzo: so che ce lo metteranno, ma non ho idea di come funzioni. Sicuramente avrà la sua utilità, ma non saprei quanta.

    Per il fatto centralizzato/distribuito: io ho apprezzato davvero la differenza quando ho svolto la Summer of Code: il repository principale era in uno stato di instabilità incredibile, e non potevo usarlo per sviluppare.

    La soluzione è stata utilizzare come base un fork stabile del progetto. Il fork integrava man mano alcuni cambiamenti ma senza distruggere le API, mentre il branch principale faceva casini.

    Il fork è un progetto indipendente, per quel che riguarda me l’esistenza di un altro repository è irrilevante.

    Allo stesso tempo, io ho pubblicato il mio repository indipendentemente, il che mi ha messo in grado di usare tutti gli strumenti per la gestione automatica delle patch e la collaborazione con altri.

    I mantainer del progetto originale e del fork stabile non hanno avuto bisogno di fornirmi credenziali per accedere al loro repository in scrittura, limitandosi a effettuare pull delle mie modifiche quando aveva senso.

    I due repository non ufficiali possono essere visti come branch classiche, ma in realtà si tratta di variazioni completamente indipendenti del progetto originale,
    Più che un feature-branching direi che assomiglia a una cosa tipo la condivisione di codice tra i vari *BSD.

    Ma lo ammetto, io preferisco darcs soprattutto perché è più facile di svn 😉

  6. Alan Franzoni says:

    riffraff:
    certo, è vero. Però ogni VCS ha le sue peculiarità, o ha il suo comando particolare per fare una determinata cosa. Se il context switching è eccessivo fra un progetto e l’altro, si rischia di diventare scemi 🙂

    Sarebbe bello che i vari VCS si “mettessero d’accordo” su un set di feature comuni e su un’implementazione comune del backend; in tal caso poi ogni tool potrebbe giocarsela sulle feature extra o sulla velocità, tutto qui.

    Effettivamente, si sentiva bisogno di due tool separati ma simili come mercurial e bazaar?

  7. Nemmeno io ho mai capito perche` c’e` gente che si ostina a usare bazaar (vedi Canonical) quando c’e` Mercurial 😛
    Bazaar e` davvero “rallentante” nello sviluppo, eppure c’e` gente come Sam Ruby che ne canta le lodi. Bah

  8. I miei due centesimi sull’argomento VCS. Ho una certa esperienza nell’uso di software di controllo di versione, anche in ambienti critici (ho coordinato il controllo di revisione di un progetto con oltre 100 tra manager e sviluppatori, su tre paesi).

    L’ultima volta che ho provato Darcs in un ambiente distribuito era così lento e pieno di bachi che lo sostituii immediatamente con tla/bazaar. Darcs ha impiegato circa 48 ore per eseguire il merge di due repository contenenti ciascuno 2Mb di sorgenti (circa), e non sto esagerando o scherzando. Dopo quell’impresa — chiamiamola così — ho deciso di abbandonarlo completamente.

    Inoltre, anche dal punto di vista teorico, la teoria delle patch – non quella della fisica, di cui non so nulla – non sta in piedi e difatti mi trovavo regolarmente col repository inutilizzabile o corrotto.

    Attualmente i due migliori VCS in circolazione sono Mercurial e GIT, che è di gran lunga il migliore di sempre, oltre che l’idea più innovativa e rivoluzionaria che sia mai apparsa in questo settore. L’unico difetto di GIT è che gira male in ambiente Microsoft, per il resto è semplicemente eccellente, a partire dalla stabilità fino alla documentazione di livello più che professionale.

    Uso GIT ogni giorno sia per i miei progetti personali (in ambiente distribuito, ma con solo due o tre sviluppatori e senza scadenze) sia per lavoro (ancora ambiente distribuito, ma molti sviluppatori e una situazione complessa, con scadenze ogni 15 giorni circa) e la differenza di produttività rispetto a qualsiasi cosa abbia provato in precedenza è impressionante.

  9. Paroline da spendere in favore di Mercurial? Ho guardato il sorgente della 0.1 prima e mi e` venuto da sorridere mettendola a confronto con la 0.9.5

  10. BazaarNG ha effettivamente un vantaggio su Mercurial, cioé la migliore integrazione con Subversion: hgsvn è ancora incompleto. Altri vantaggi non ne vedo.

    Certo, se Canonical avesse investito su Mercurial anziché riscrivere Bazaar, forse sarebbe stato meglio per tutti. Ma capisco che sia difficile orientare un progetto strategico, se controllato da altri.

    Io non mi lamento per la disponibilità di più strumenti, credo che i vantaggi superino le scomodità.

  11. A me basterebbe un formato di interscambio unificato 😛

  12. paolo: grazie, dei due cent, sono molto apprezzati.
    Se ti andasse di scrivere un articoletto su git sarebbe apprezzato 🙂

Policy per i commenti: Apprezzo moltissimo i vostri commenti, critiche incluse. Per evitare spam e troll, e far rimanere il discorso civile, i commenti sono moderati e prontamente approvati poco dopo il loro invio.