Unione: Hg / Git vs. SVN



Answers

Anch'io ho cercato un caso in cui, ad esempio, Subversion non riesce a fondere un ramo e Mercurial (e Git, Bazaar, ...) fa la cosa giusta.

Il libro SVN descrive come i file rinominati vengono uniti in modo errato . Questo vale per Subversion 1.5 , 1.6 , 1.7 e 1.8 ! Ho provato a ricreare la situazione di seguito:

cd /tmp
rm -rf svn-repo svn-checkout
svnadmin create svn-repo
svn checkout file:///tmp/svn-repo svn-checkout
cd svn-checkout
mkdir trunk branches
echo 'Goodbye, World!' > trunk/hello.txt
svn add trunk branches
svn commit -m 'Initial import.'
svn copy '^/trunk' '^/branches/rename' -m 'Create branch.'
svn switch '^/trunk' .
echo 'Hello, World!' > hello.txt
svn commit -m 'Update on trunk.'
svn switch '^/branches/rename' .
svn rename hello.txt hello.en.txt
svn commit -m 'Rename on branch.'
svn switch '^/trunk' .
svn merge --reintegrate '^/branches/rename'

Secondo il libro, l'unione dovrebbe terminare in modo pulito, ma con dati errati nel file rinominato poiché l'aggiornamento sul trunk è stato dimenticato. Invece ottengo un conflitto ad albero (questo è con Subversion 1.6.17, la versione più recente in Debian al momento della scrittura):

--- Merging differences between repository URLs into '.':
A    hello.en.txt
   C hello.txt
Summary of conflicts:
  Tree conflicts: 1

Non dovrebbe esserci alcun conflitto - l'aggiornamento dovrebbe essere unito al nuovo nome del file. Mentre Subversion fallisce, Mercurial lo gestisce correttamente:

rm -rf /tmp/hg-repo
hg init /tmp/hg-repo
cd /tmp/hg-repo
echo 'Goodbye, World!' > hello.txt
hg add hello.txt
hg commit -m 'Initial import.'
echo 'Hello, World!' > hello.txt
hg commit -m 'Update.'
hg update 0
hg rename hello.txt hello.en.txt
hg commit -m 'Rename.'
hg merge

Prima dell'unione, il repository appare come questo (da hg glog ):

@  changeset:   2:6502899164cc
|  tag:         tip
|  parent:      0:d08bcebadd9e
|  user:        Martin Geisler 
|  date:        Thu Apr 01 12:29:19 2010 +0200
|  summary:     Rename.
|
| o  changeset:   1:9d06fa155634
|/   user:        Martin Geisler 
|    date:        Thu Apr 01 12:29:18 2010 +0200
|    summary:     Update.
|
o  changeset:   0:d08bcebadd9e
   user:        Martin Geisler 
   date:        Thu Apr 01 12:29:18 2010 +0200
   summary:     Initial import.

L'output dell'unione è:

merging hello.en.txt and hello.txt to hello.en.txt
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

In altre parole: Mercurial ha preso la modifica dalla revisione 1 e l'ha unita al nuovo nome del file dalla revisione 2 ( hello.en.txt ). Gestire questo caso è ovviamente essenziale per supportare il refactoring e il refactoring è esattamente il tipo di cosa che vorrete fare su una filiale.

Question

Ho letto spesso che Hg (e Git e ...) sono migliori per l'unione di SVN, ma non ho mai visto esempi pratici di dove Hg / Git possa unire qualcosa in cui SVN fallisce (o dove SVN necessita di intervento manuale). Potresti pubblicare alcuni elenchi passo-passo delle operazioni branch / modify / commit /...- che mostrano dove SVN fallirebbe mentre Hg / Git si muove felicemente? Casi pratici, non estremamente eccezionali, per favore ...

Qualche retroscena: abbiamo alcune decine di sviluppatori che lavorano su progetti usando SVN, con ogni progetto (o gruppo di progetti simili) nel proprio repository. Sappiamo come applicare release e feature branch in modo da non incorrere in problemi molto spesso (ad esempio, siamo stati lì, ma abbiamo imparato a superare i problemi di Joel di "un programmatore che causa un trauma a tutta la squadra" o "aver bisogno di sei sviluppatori per due settimane per reintegrare un ramo"). Abbiamo rami di rilascio che sono molto stabili e usati solo per applicare correzioni di bug. Abbiamo tronchi che dovrebbero essere abbastanza stabili da essere in grado di creare un rilascio entro una settimana. E abbiamo feature-branch su cui singoli sviluppatori o gruppi di sviluppatori possono lavorare. Sì, vengono cancellati dopo il reinserimento in modo che non ingombrino il repository. ;)

Quindi sto ancora cercando di trovare i vantaggi di Hg / Git su SVN. Mi piacerebbe avere qualche esperienza pratica, ma non ci sono progetti più grandi che potremmo passare a Hg / Git, quindi sono bloccato a giocare con piccoli progetti artificiali che contengono solo alcuni file creati. E sto cercando alcuni casi in cui puoi percepire l'impressionante potere di Hg / Git, dal momento che finora ho spesso letto su di loro ma non sono riuscito a trovarli da solo.




Di recente abbiamo migrato da SVN a GIT e abbiamo affrontato questa stessa incertezza. C'era un sacco di prove aneddotiche sul fatto che GIT fosse migliore, ma era difficile trovare esempi.

Posso dirvi, però, che GIT è MOLTO BELLO nella fusione rispetto a SVN. Questo è ovviamente aneddotico, ma c'è un tavolo da seguire.

Ecco alcune delle cose che abbiamo trovato:

  • SVN soleva sollevare un sacco di conflitti tra alberi in situazioni in cui sembrava non doverlo fare. Non siamo mai arrivati ​​a fondo, ma non succede in GIT.
  • Mentre meglio, GIT è significativamente più complicato. Dedica un po 'di tempo alla formazione.
  • Eravamo abituati a Tortoise SVN, che ci piaceva. GIT Tortoise non è buono e questo potrebbe scoraggiare. Comunque ora utilizzo la riga di comando GIT che preferisco di gran lunga a Tortoise SVN o a qualsiasi GUI GIT.

Durante la valutazione di GIT abbiamo eseguito i seguenti test. Questi mostrano GIT come il vincitore quando si tratta di unire, ma non di molto. In pratica la differenza è molto più grande, ma suppongo che non siamo riusciti a replicare le situazioni che SVN gestisce male.




Prima della sovversione 1.5 (se non sbaglio), la sovversione aveva uno svantaggio significativo in quanto non ricordava la cronologia delle unioni.

Diamo un'occhiata al caso delineato da VonC:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - A - x (v2-only)
           \
             x - B - x (wss)

Notare le revisioni A e B. Dire che le modifiche unite dalla revisione A sul ramo "wss" al ramo "v2-only" alla revisione B (per qualsiasi motivo), ma hanno continuato ad utilizzare entrambi i rami. Se si tenta di unire nuovamente i due rami usando mercurial, si uniranno solo le modifiche dopo le revisioni A e B. Con la sovversione, si dovrà unire tutto, come se prima non si fosse fatto unire.

Questo è un esempio tratto dalla mia esperienza personale, in cui la fusione da B ad A ha richiesto diverse ore a causa del volume di codice: sarebbe stato un vero dolore ripetere ancora , il che sarebbe stato il caso di subversion pre-1.5.

Un'altra, probabilmente più rilevante differenza nel comportamento di fusione da Hginit: Subversion Re-education :

Immagina che tu ed io stiamo lavorando su un codice, e lo ramifichiamo, e ognuno di noi va nei nostri spazi di lavoro separati e apporta molte e molte modifiche a quel codice separatamente, quindi hanno diverguto parecchio.

Quando dobbiamo unirci, Subversion prova a guardare entrambe le revisioni, il mio codice modificato e il codice modificato, e cerca di indovinare come distruggerli insieme in un unico grande disastro. Di solito fallisce, producendo pagine e pagine di "conflitti di fusione" che non sono realmente conflitti, semplicemente luoghi in cui Subversion non riesce a capire cosa abbiamo fatto.

Al contrario, mentre lavoravamo separatamente in Mercurial, Mercurial era impegnato a tenere una serie di changeset. E così, quando vogliamo unire il nostro codice, Mercurial ha davvero molte più informazioni: sa cosa ognuno di noi ha cambiato e può riapplicare quei cambiamenti, piuttosto che guardare solo il prodotto finale e cercare di indovinare come metterlo insieme.

In breve, il modo in cui Mercurial analizza le differenze è (era?) Superiore a quello di sovversione.




Links