Fusione: Hg / Git vs. SVN


144

Ho letto spesso che Hg (e Git e ...) sono migliori nella fusione di SVN, ma non ho mai visto esempi pratici di dove Hg / Git può fondere qualcosa in cui SVN fallisce (o dove SVN ha bisogno di un intervento manuale). Potresti pubblicare alcuni elenchi passo-passo delle operazioni di branch / modifica / commit /...- che mostrano dove SVN fallirebbe mentre Hg / Git passa felicemente? Casi pratici, non molto eccezionali, per favore ...

Alcuni 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 i rami di rilascio e funzionalità in modo da non incorrere molto spesso in problemi (ovvero, siamo stati lì, ma abbiamo imparato a superare i problemi di Joel di "un programmatore che causa traumi a tutto il team" o "occorrono sei sviluppatori per due settimane per reintegrare un ramo"). Abbiamo rami di rilascio molto stabili e usati solo per applicare correzioni di bug. Abbiamo tronchi che dovrebbero essere abbastanza stabili da poter creare una versione entro una settimana. E abbiamo rami di funzioni su cui singoli sviluppatori o gruppi di sviluppatori possono lavorare. Sì, vengono eliminati dopo il reinserimento in modo da non ingombrare il repository. ;)

Quindi sto ancora cercando di trovare i vantaggi di Hg / Git rispetto a SVN. Mi piacerebbe fare un po 'di esperienza pratica, ma non ci sono ancora progetti più grandi che potremmo passare a Hg / Git, quindi sono bloccato a giocare con piccoli progetti artificiali che contengono solo pochi file inventati. E sto cercando alcuni casi in cui puoi sentire il potere impressionante di Hg / Git, poiché finora ho letto spesso su di loro ma non sono riuscito a trovarli da solo.


2
Penso che dovresti prestare attenzione ai duplicati esatti: stackoverflow.com/questions/43995/… stackoverflow.com/questions/459891/…
P Shved

11
Avevo già letto il primo, l'altro era nuovo. Ma hanno già 1-2 anni e sembrano riguardare principalmente i problemi pre-svn-1.5 (dove svn non aveva ancora il monitoraggio delle unioni).
stmax

2
Solo un commento in cui puoi anche inserire Bazaar con git / hg come un altro DVCS che gestirà correttamente i problemi di seguito. E dal momento che hai menzionato il tentativo di trovare vantaggi: un semplice vantaggio logistico di git / hg / bzr è che i rami non sono globali come lo sono con svn. Non devi vedere 67 rami, quando solo una coppia si applica a te. Ognuno svolge il proprio lavoro in filiali "private" e quindi utilizza l'eccellente funzionalità di unione per ricollegarsi senza sudare se la fusione funzionerà nel 99% dei casi.
wadesworld,

5
@wade: vedi le filiali "private" come un vantaggio in un ambiente aziendale? sono preoccupato per i backup. ho spesso filiali che vivono per 1-2 mesi prima del reinserimento ..
stmax

9
@stmax: una preoccupazione valida. Tuttavia, ciò che trovi in ​​molti ambienti aziendali con sovversione è che le persone trattengono il check-in fino a quando il loro codice non è perfetto e tu hai la stessa esposizione lì.
wadesworld,

Risposte:


91

Non utilizzo Subversion da solo, ma dalle note di rilascio di Subversion 1.5: Unisci tracciamento (di base) sembra che ci siano le seguenti differenze rispetto al modo in cui il monitoraggio di unione funziona nei sistemi di controllo della versione full- DAG come Git o Mercurial.

  • L'unione di trunk in branch è diversa dall'unione di branch in trunk: per qualche motivo l'unione di trunk in branch richiede --reintegrateun'opzione svn merge.

    Nei sistemi di controllo della versione distribuita come Git o Mercurial non esiste alcuna differenza tecnica tra trunk e branch: tutti i rami sono creati uguali (tuttavia potrebbe esserci una differenza sociale ). La fusione in entrambe le direzioni avviene allo stesso modo.

  • Devi fornire la nuova opzione -g( --use-merge-history) per svn loge svn blametenere conto del monitoraggio delle unioni.

    In Git e Mercurial il monitoraggio delle unioni viene automaticamente preso in considerazione quando si visualizzano cronologia (registro) e colpa. In Git puoi richiedere di seguire il primo genitore solo con --first-parent(immagino che esiste un'opzione simile anche per Mercurial) per "scartare" unendo le informazioni di tracciamento git log.

  • Da quello che capisco svn:mergeinfoi negozi di proprietà informazioni sul percorso relative ai conflitti (Subversion è basata sul changeset), mentre in Git e Mercurial si tratta semplicemente di eseguire il commit di oggetti che possono avere più di un genitore.

  • La sottosezione "Problemi noti" per il monitoraggio delle unioni in Subversion suggerisce che l'unione ripetuta / ciclica / riflettente potrebbe non funzionare correttamente. Significa che con le seguenti storie la seconda unione potrebbe non fare la cosa giusta ('A' può essere tronco o ramo, e 'B' può essere ramo o tronco, rispettivamente):

    * --- * --- x --- * --- y --- * --- * --- * --- M2 <- A
             \ \ /
              - * ---- M1 --- * --- * --- / <- B
    

    Nel caso in cui l'arte ASCII precedente si rompa: il ramo 'B' viene creato (biforcato) dal ramo 'A' alla revisione 'x', quindi il ramo 'A' viene unito alla revisione 'y' nel ramo 'B' come unire 'M1', e infine il ramo 'B' viene unito al ramo 'A' come unire 'M2'.

    * --- * --- x --- * ----- M1 - * --- * --- M2 <- A
             \ / / 
              \ - * --- y --- * --- * --- / <- B
    

    Nel caso in cui l'arte ASCII precedente si rompa: il ramo 'B' viene creato (biforcuto) dal ramo 'A' alla revisione 'x', viene unito al ramo 'A' in 'y' come 'M1', e successivamente fusa di nuovo nel ramo 'A' come 'M2'.

  • Subversion potrebbe non supportare il caso avanzato di unione incrociata .

    * --- b ----- B1 - M1 - * --- M3
         \ \ / /
          \ X /
           \ / \ /
            \ - B2 - M2 - *
    

    Git gestisce bene questa situazione in pratica usando una strategia di unione "ricorsiva". Non sono sicuro di Mercurial.

  • In "Problemi noti" è presente l'avvertenza che l'unione del tracciamento potrebbe non funzionare con la ridenominazione dei file, ad esempio quando un lato rinomina il file (e forse lo modifica) e il secondo lato modifica il file senza rinominarlo (con il vecchio nome).

    Sia Git che Mercurial gestiscono in pratica un caso del genere: Git utilizza il rilevamento della ridenominazione , Mercurial utilizza il monitoraggio della ridenominazione .

HTH


in qualche modo (errore nel parser Markdown?) la parte dopo il <pre>...</pre>blocco non è rientrata come dovrebbe essere ...
Jakub Narębski

1
+1 per i numerosi esempi dettagliati. Non capisco ancora perché l'esempio nella prima arte ASCII potrebbe causare problemi. sembra il modo standard di trattare i rami delle caratteristiche: supponiamo che A sia il tronco, B sia un ramo di caratteristiche. unisci settimanalmente da A a B e quando hai finito con la funzione unisci tutto da B a A e poi elimini B. che ha sempre funzionato per me. ho frainteso il diagramma?
stmax,

1
Si noti che non so (non ho verificato) che gli esempi sopra riportati creino davvero problemi in Subversion . I nomi e l'unione incrociata sono un vero problema in SVN, credo.
Jakub Narębski,

2
reintegrare le fusioni è un'opzione speciale per aiutarti nel caso più comune durante la fusione: non c'è nemmeno differenza tecnica tra filiali e trunk in svn. Tendo a non usarlo mai e ad attenermi all'opzione di unione standard. Tuttavia, l'unico problema con svn merge è che tratta una mossa / rinomina come cancellazione + aggiunta.
gbjbaanb,

--reintegrateè deprecato.
naught101

120

Anch'io ho cercato un caso in cui, per 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 seguente:

cd / tmp
rm - rf svn - repo svn - checkout
svnadmin create svn - repo
file di checkout svn : /// tmp / svn - repo svn - checkout
cd svn - checkout
rami del tronco di mkdir
echo "Arrivederci, mondo!" > baule / ciao . testo 
svn aggiungi i rami del tronco
svn commit - m 'Importazione iniziale.' 
svn copia '^ / trunk' '^ / rami / rinomina' - m 'Crea ramo.' 
interruttore svn '^ / trunk' . 
echo "Ciao, mondo!" > ciao . testo    
svn commit - m 'Aggiornamento su trunk.' 
interruttore svn '^ / rami / rinomina' . 
svn rinomina ciao . ciao txt . en . testo 
svn commit - m 'Rinomina sul ramo.' 
interruttore svn '^ / trunk' . 
svn merge - reintegrare '^ / rami / rinomina' 

Secondo il libro, l'unione dovrebbe finire in modo pulito, ma con dati errati nel file rinominato poiché l'aggiornamento su trunkè stato dimenticato. Invece ho un conflitto tra alberi (questo è con Subversion 1.6.17, la versione più recente di Debian al momento della stesura):

--- Unione delle differenze tra gli URL del repository in ".":
A hello.en.txt
   C hello.txt
Riepilogo dei conflitti:
  Conflitti sugli alberi: 1

Non dovrebbe esserci alcun conflitto: l'aggiornamento deve 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 così (da hg glog):

@ changeset: 2: 6502899164cc
| tag: suggerimento
| genitore: 0: d08bcebadd9e
| utente: Martin Geisler
| data: gio 01 apr 12:29:19 2010 +0200
| sommario: Rinomina.
|
| o changeset: 1: 9d06fa155634
| / utente: Martin Geisler 
| data: gio 01 apr 12:29:18 2010 +0200
| riepilogo: aggiornamento.
|
o changeset: 0: d08bcebadd9e
   utente: Martin Geisler 
   data: gio 01 apr 12:29:18 2010 +0200
   riepilogo: importazione iniziale.

L'output dell'unione è:

fusione di hello.en.txt e hello.txt in hello.en.txt
0 file aggiornati, 1 file uniti, 0 file rimossi, 0 file non risolti
(unione di ramo, non dimenticare di impegnare)

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


+1 per un esempio dettagliato, puoi toccare la tastiera e vedere di persona cosa succede. Come Mercurial Noob, mi chiedo se la versione hg di questo esempio sia seguita in modo ovvio, riga per riga?
DarenW,

4
@DarenW: ho aggiunto i corrispondenti comandi Mercurial, spero che renda le cose più chiare!
Martin Geisler

17

Senza parlare dei soliti vantaggi (commit offline, processo di pubblicazione , ...) ecco un esempio di "unione" che mi piace:

Lo scenario principale che continuo a vedere è un ramo in cui ... due attività non correlate sono effettivamente sviluppate
(è iniziata da una funzionalità, ma ha portato allo sviluppo di questa altra funzionalità.
O è iniziata da una patch, ma ha portato alla sviluppo di un'altra caratteristica).

Come unire solo una delle due funzionalità sul ramo principale?
Oppure come isolare le due caratteristiche nei loro rami?

Potresti provare a generare un qualche tipo di patch, il problema è che non sei più sicuro delle dipendenze funzionali che avrebbero potuto esistere tra:

  • i commit (o la revisione per SVN) utilizzati nelle patch
  • l'altro non fa parte della patch

Git (e anche Mercurial suppongo) proponga l'opzione rebase --onto per rebase (resetta la radice del ramo) parte di un ramo:

Dal post di Jefromi

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

puoi districare questa situazione in cui hai patch per la v2 e una nuova funzionalità wss in:

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

, consentendoti di:

  • testare ogni ramo in modo isolato per verificare se tutto viene compilato / funziona come previsto
  • unisci solo ciò che vuoi mantenere.

L'altra caratteristica che mi piace (la cui influenza si fonde) è la capacità di eseguire lo squash di commit (in un ramo non ancora spinto in un altro repository) per presentare:

  • una storia più pulita
  • commit che sono più coerenti (invece di commit1 per function1, commit2 per function2, commit3 di nuovo per function1 ...)

Ciò garantisce fusioni che sono molto più facili, con meno conflitti.


svn non ha commit offline? rofl? come si può anche considerare in remoto di usarlo se è così?
o0 '.

@Lohoris Quando uscì SVN, non c'erano DVCS open source ampiamente utilizzati; a questo punto, penso che sia per lo più inerzia che la gente lo usi ancora.
Max Nanasy,

@MaxNanasy un pessimo tipo di inerzia ... tuttavia, sceglierlo ora sarebbe semplicemente stupido.
o0 '.

Gli commit di @Lohoris Online (più precisamente, centralizzati) non sono un grosso problema in un piccolo team in cui il repository può essere semplicemente su un server locale condiviso. I DVCS sono stati per lo più inventati per grandi team distribuiti geograficamente (sia git che mercurial erano destinati a gestire il codice del kernel Linux) e progetti open source (da cui la popolarità di GitHub). L'inerzia può anche essere vista come una valutazione dei rischi rispetto ai benefici derivanti dalla modifica di uno strumento centrale nel flusso di lavoro di una squadra.
IMSoP,

1
@Lohoris Penso che tu frainteso il mio punto su DB, firewall, ecc: c'è poco punto me di essere in grado di impegnarsi sulla mia macchina a casa se non posso effettivamente eseguito quel codice prima. Ho potuto lavorare cieco, ma il fatto che non riesco a commettere le cose da qualche parte, non sarebbe la cosa principale mi rimandare.
IMSoP,

8

Di recente siamo migrati da SVN a GIT e abbiamo dovuto affrontare questa stessa incertezza. C'erano molte prove aneddotiche che il GIT fosse migliore, ma era difficile imbattersi in qualche esempio.

Posso dirti, però, che GIT è MOLTO MEGLIO nel fondersi rispetto a SVN. Questo è ovviamente aneddotico, ma c'è una tabella da seguire.

Ecco alcune delle cose che abbiamo trovato:

  • SVN solleva molti conflitti tra alberi in situazioni in cui sembra che non dovrebbe. Non siamo mai arrivati ​​al fondo di questo, ma non succede in GIT.
  • Sebbene migliore, GIT è significativamente più complicato. Trascorrere del tempo in allenamento.
  • Eravamo abituati a Tortoise SVN, che ci piaceva. Tortoise GIT non è così buono e questo potrebbe scoraggiarti. Tuttavia ora uso la riga di comando GIT che preferisco di gran lunga a Tortoise SVN o ad una qualsiasi delle GUI di GIT.

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

Valutazione di fusione GIT vs SVN


5

Altri hanno trattato gli aspetti più teorici di questo. Forse posso dare una prospettiva più pratica.

Attualmente sto lavorando per un'azienda che utilizza SVN in un modello di sviluppo "ramo di funzionalità". Questo è:

  • Non è possibile eseguire alcun lavoro sul trunk
  • Ogni sviluppatore può avere i propri rami
  • Le filiali dovrebbero durare per la durata dell'attività svolta
  • Ogni attività dovrebbe avere il proprio ramo
  • Le fusioni di nuovo al tronco devono essere autorizzate (normalmente tramite bugzilla)
  • Nei momenti in cui sono necessari alti livelli di controllo, un gatekeeper può eseguire le fusioni

In generale, funziona. SVN può essere utilizzato per un flusso come questo, ma non è perfetto. Ci sono alcuni aspetti di SVN che ostacolano e modellano il comportamento umano. Questo gli dà alcuni aspetti negativi.

  • Abbiamo avuto alcuni problemi con le persone che si ramificano da punti inferiori a ^/trunk. Questa cucciolata unisce i record di informazioni in tutto l'albero e alla fine interrompe il tracciamento della fusione. Iniziano ad apparire falsi conflitti e regna la confusione.
  • Raccogliere le modifiche dal tronco in un ramo è relativamente semplice. svn mergefa quello che vuoi. La fusione delle modifiche indietro richiede (ci viene detto) --reintegratesul comando Unisci. Non ho mai veramente capito questo interruttore, ma significa che il ramo non può più essere unito nel tronco. Ciò significa che è un ramo morto e devi crearne uno nuovo per continuare a lavorare. (Vedi nota)
  • L'intera attività di eseguire operazioni sul server tramite URL durante la creazione e l'eliminazione di filiali confonde e spaventa le persone. Quindi lo evitano.
  • Passare da un ramo all'altro è facile sbagliarsi, lasciando parte di un albero guardando il ramo A, mentre lasciando un'altra parte guardando il ramo B. Quindi le persone preferiscono fare tutto il loro lavoro in un ramo.

Quello che tende a succedere è che un ingegnere crea una filiale il primo giorno. Inizia il suo lavoro e se ne dimentica. Qualche tempo dopo arriva un boss e gli chiede se può rilasciare il suo lavoro nel bagagliaio. L'ingegnere teme questo giorno perché reintegrare significa:

  • Unire il suo ramo longevo nel tronco e risolvere tutti i conflitti e rilasciare codice non correlato che avrebbe dovuto essere in un ramo separato, ma non lo era.
  • Cancellare il suo ramo
  • Creare un nuovo ramo
  • Passando la sua copia di lavoro al nuovo ramo

... e poiché l'ingegnere lo fa il meno possibile, non riescono a ricordare l '"incantesimo magico" per fare ogni passo. Succedono interruttori e URL errati, e improvvisamente si trovano in un pasticcio e vanno a prendere "l'esperto".

Alla fine tutto si risolve e le persone imparano a gestire le carenze, ma ogni nuovo antipasto subisce gli stessi problemi. L'eventuale realtà (al contrario di ciò che ho esposto all'inizio) è:

  • Non viene eseguito alcun lavoro sul trunk
  • Ogni sviluppatore ha un ramo principale
  • I rami durano fino a quando il lavoro deve essere rilasciato
  • Le correzioni di bug con ticketing tendono ad avere il proprio ramo
  • Le fusioni sul tronco vengono eseguite quando autorizzate

...ma...

  • A volte il lavoro lo rende un tronco quando non dovrebbe perché è nello stesso ramo di qualcos'altro.
  • Le persone evitano tutte le fusioni (anche cose facili), quindi le persone spesso lavorano nelle loro piccole bolle
  • Le grandi fusioni tendono a verificarsi e causano una quantità limitata di caos.

Per fortuna il team è abbastanza piccolo da farcela, ma non si ridimensionerebbe. Il fatto è che niente di tutto questo è un problema con CVCS, ma soprattutto perché le fusioni non sono così importanti come in DVCS non sono così fluide. Quella "fusione per attrito" provoca un comportamento, il che significa che un modello "Ramo delle caratteristiche" inizia a rompersi. Le buone fusioni devono essere una caratteristica di tutti i VCS, non solo dei DVCS.


In base a questo c'è ora un --record-onlyinterruttore che potrebbe essere usato per risolvere il --reintegrateproblema, e apparentemente v1.8 sceglie quando fare un reinserimento automatico, e non causa la morte del ramo in seguito


A quanto ho capito, l'opzione --reintegrate dice a svn che hai già risolto cambiamenti contrastanti quando ti sei unito al ramo delle caratteristiche. In effetti, piuttosto che trattarlo come una patch, sovrascrive interi file con la versione del ramo, avendo già verificato nella cronologia di unione che tutte le revisioni del trunk sono state unite nel ramo.
IMSoP,

@IMSoP: forse, ha un senso. Ciò non mi spiega perché fosse necessario o perché rendesse impossibili ulteriori fusioni da quel ramo. Non ha aiutato il fatto che l'opzione non fosse ampiamente documentata.
Paul S,

L'ho mai usato solo tramite TortoiseSVN, dove è stato sempre ben spiegato nell'interfaccia utente di merge. Credo che SVN 1.8 scelga automaticamente la giusta strategia e non abbia bisogno di un'opzione separata, ma non so se hanno corretto l'algoritmo di unione normale per gestire correttamente un ramo che è stato ripristinato in questo modo.
IMSoP,

3

Prima della sovversione 1.5 (se non sbaglio), la sovversione presentava uno svantaggio significativo in quanto non ricordava la storia di fusione.

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)

Nota le revisioni A e B. Supponi di aver unito le modifiche dalla revisione A sul ramo "wss" al ramo "solo v2" alla revisione B (per qualsiasi motivo), ma hai continuato a utilizzare entrambi i rami. Se provassi a unire di nuovo i due rami usando mercurial, unirebbero le modifiche solo dopo le revisioni A e B. Con la sovversione, dovresti unire tutto, come se non avessi mai fatto una fusione prima.

Questo è un esempio dalla mia esperienza personale, in cui la fusione da B ad A sono volute diverse ore a causa del volume di codice: che sarebbe stato un vero e proprio dolore di passare attraverso di nuovo , che sarebbe stato il caso con la sovversione pre-1.5.

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

Immagina che tu e io stiamo lavorando su un po 'di codice, e noi ramifichiamo quel codice, e ognuno di noi si sposta nelle nostre aree di lavoro separate e apporta molte e molte modifiche a quel codice separatamente, quindi sono divergenti abbastanza.

Quando dobbiamo unirci, Subversion cerca di esaminare entrambe le revisioni — il mio codice modificato e il tuo codice modificato — e cerca di indovinare come frantumarli insieme in un unico grande disordine. Di solito fallisce, producendo pagine e pagine di "conflitti di unione" che non sono realmente conflitti, semplicemente luoghi in cui Subversion non è riuscito a capire cosa abbiamo fatto.

Al contrario, mentre lavoravamo separatamente in Mercurial, Mercurial era impegnata a mantenere una serie di cambiamenti. E così, quando vogliamo unire il nostro codice, Mercurial in realtà ha molte più informazioni: sa cosa è cambiato ognuno di noi e può riapplicare quei cambiamenti, piuttosto che guardare semplicemente il prodotto finale e provare a indovinare come metterlo insieme.

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


5
ho letto hginit. peccato che non mostri esempi più pratici di dove hg sta facendo meglio di svn .. fondamentalmente ti dice di "fidarti di joel" che hg è semplicemente migliore. i semplici esempi che ha mostrato potrebbero probabilmente essere fatti anche con svn .. in realtà è per questo che ho aperto questa domanda.
stmax,

1
Sulla base di ciò che viene detto, mi viene in mente l'ingenua domanda: e se l'algoritmo di unione di Mercurial fosse messo in Subversion? Svn sarebbe quindi buono come hg? No, perché il vantaggio di hg è nell'organizzazione di livello superiore, non nella matematica testuale di basso livello della fusione di righe da file. Questa è la nuova idea di cui gli utenti di svn hanno bisogno per grok.
DarenW,

@stmax: capisco cosa intendi. Tuttavia, l'opinione di Joel o di chiunque altro non ha molta importanza: una tecnologia è migliore dell'altra (per una serie di casi d'uso) oppure no. @DarenW e @stmax: dalla mia esperienza personale, Hg vince a mani basse grazie alle sue operazioni distribuite (non sono sempre connesso), alle prestazioni (molte operazioni locali), alla ramificazione estremamente intuitiva potenziata da un algoritmo di unione superiore, hg rollback, output log logato, hg glog, cartella .hg singola ... Potrei semplicemente andare avanti e avanti e avanti ... qualsiasi cosa diversa da forse git e bazaar sembra una camicia di forza.
Tomislav Nakic-Alfirevic,

Il commento hg citato su "changeset" mi sembra piuttosto inaccurato. SVN sa perfettamente quali cambiamenti sta fondendo (un changeset è fondamentalmente la differenza tra due snapshot e viceversa, giusto?), E può applicarli a turno se lo desidera; certamente non deve "indovinare" nulla. Se crea "un grande disastro", questo è un problema di implementazione, non qualcosa di fondamentale per la progettazione. Il problema principale che è difficile da risolvere in aggiunta all'attuale design dell'architettura è lo spostamento / copia / rinomina dei file.
IMSoP,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.