Cosa c'è di così difficile nelle fusioni SVN?


28

Possibile duplicato:
sono un fanatico di Subversion, perché dovrei considerare o meno Mercurial o Git o qualsiasi altro DVCS?

Ogni tanto senti qualcuno dire che il controllo della versione distribuita (Git, HG) è intrinsecamente migliore del controllo centralizzato della versione (come SVN) perché la fusione è difficile e dolorosa in SVN. Il fatto è che non ho mai avuto problemi con la fusione in SVN, e poiché hai sempre e solo sentito quell'affermazione fatta dai sostenitori di DVCS e non dagli utenti reali di SVN, tende a ricordarmi di quegli odiosi spot pubblicitari in TV dove prova a venderti qualcosa di cui non hai bisogno facendo in modo che attori confusi fingano che la cosa che hai già e funzioni bene sia incredibilmente difficile da usare.

E il caso d'uso che viene invariabilmente sollevato sta ricongiungendo un ramo, il che mi ricorda ancora una volta quelle pubblicità dei prodotti di paglia; se sai cosa stai facendo, non dovresti (e non dovresti mai) unire nuovamente un ramo in primo luogo. (Certo che è difficile da fare quando stai facendo qualcosa di fondamentalmente sbagliato e sciocco!)

Quindi, scontando il ridicolo caso d'uso di Strawman, cosa c'è nella fusione SVN che è intrinsecamente più difficile della fusione in un sistema DVCS?


6
Devo ancora lavorare in un ambiente in cui si uniscono filiali lunghe mesi e usano il controllo della versione distribuita. Gli unici posti in cui ho lavorato in cui rami così longevi usavano TFS / Subversion. Mi aspetto che rami così longevi sarebbero difficili da fondere anche con i DVCS.
Oded,

13
@MasonWheeler Sono perplesso. A che cosa serve un VCS? Ho visto e letto che una (delle tante) pratiche raccomandate è quella di avere rami di funzionalità. In questo caso è obbligatorio fondersi di nuovo al tronco. O ho frainteso qualcosa? (sì, la metafora dell'albero si spezza, ma non era poi tanto utile iniziare con l'IMO)
Andres F.

9
@MasonWheeler: Penso che stai prendendo l'analogia dell'albero un po 'troppo alla lettera.
whatsisname


8
@MasonWheeler di quanti diversi ambienti di sviluppo hai esperienza, se non hai mai sentito parlare della fusione con il trunk? Alcuni negozi hanno un tronco stabile e filiali sperimentali, nel qual caso la raccolta delle ciliegie da successo a stabile è un evento regolare.
itsbruce,

Risposte:


25

È perché a svn mancavano le strutture dati appropriate per determinare con precisione l'ultimo antenato comune dei due rami. Questo non è un grosso problema per un ramo che viene unito solo una volta, ma può causare molti conflitti di unione errati in situazioni in cui più rami vengono uniti più volte.

Non seguo molto da vicino svn, ma la mia comprensione è che quei particolari problemi tecnici sono stati risolti nelle ultime versioni. Tuttavia, non è stato risolto abbastanza presto per dissipare il mito e le persone che hanno provato DVCS per le fusioni si sono bloccate per altri motivi.


47

se sai cosa stai facendo, non dovresti (e non dovresti mai) unire nuovamente un ramo in primo luogo. (Certo che è difficile da fare quando stai facendo qualcosa di fondamentalmente sbagliato e sciocco!)

E qui sta la fonte della tua confusione e l'intero problema in generale.

Dici che fondere i rami è "fondamentalmente sbagliato e sciocco". Bene, questo è esattamente il problema: stai pensando ai rami come cose che non dovrebbero essere unite. Perché? Perché sei un utente SVN che sa che l'unione dei rami è difficile . Pertanto, non lo fai mai e incoraggi gli altri a non farlo. Sei stato addestrato per evitare la fusione; hai sviluppato tecniche che usi per evitare l' unione.

Sono un utente Mercurial. Anche sui miei progetti, in cui sono l'unico sviluppatore, unisco i rami in ogni momento . Ho un ramo di rilascio, in cui ho messo una correzione. Bene, lo fondo di nuovo nella linea principale in modo che la correzione vada lì.

Se avessi usato SVN, avrei adottato una struttura completamente diversa della base di codice. Perché? Perché SVN rende difficili le fusioni e quindi sviluppi modi di dire e tecniche per evitare fusioni complesse.

I DVCS rendono facili le fusioni complesse perché sono lo stato predefinito . Tutto è un ramo, più o meno, in un DVCS. Quindi l'intera struttura è stata costruita da zero per facilitare la fusione. Ciò consente di sviluppare un flusso di lavoro che utilizza l'unione su base giornaliera, anziché il flusso di lavoro SVN in cui non si utilizza mai l'unione.

Il semplice fatto è questo: dovresti avvicinarti a un DVCS in un modo diverso rispetto a SVN. È necessario utilizzare i modi di dire appropriati per questi tipi molto diversi di sistemi di controllo della versione. In SVN, adotti i modi di dire che non implicano la fusione perché le fusioni sono difficili. In DVCS, adotti i modi di dire che usano spesso le fusioni perché non sono un grosso problema.

Strumento giusto per il lavoro giusto.

Il fatto è che il flusso di lavoro incentrato sulla fusione è molto più semplice e facile da usare rispetto al flusso di lavoro in stile SVN in cui non si uniscono le cose. È più facile vedere quando qualcosa dal ramo di rilascio è stato portato nel ramo di sviluppo. È più facile vedere le varie interazioni tra i rami. È facile creare rami di test per le cose, quindi tagliarli se il test non funziona. E così via.

Davvero, Joel lo spiega molto meglio di me . Dovresti leggerlo bene.


15
@ Mason: in che modo non si sta allenando? Sei stato addestrato per usare SVN in uno stile SVN. E lo stile SVN è di non usare l'unione. Quindi, sei stato addestrato a non usare o addirittura prendere in considerazione la fusione di cose. Ecco perché non ti è mai venuto in mente; perché hai usato un sistema che lo rende difficile.
Nicol Bolas,

5
C'è una grande differenza tra "non addestrato a" e "addestrato a non".
Mason Wheeler,

8
@MasonWheeler: No, non c'è. Se non ti viene insegnato correttamente come fare qualcosa, allora sei implicitamente addestrato a non farlo. Non è nel tuo repertorio di idiomi che puoi impiegare per risolvere un problema. Pertanto, non è possibile utilizzarlo per risolvere i problemi. L'effetto non è diverso dall'essere detto di non fondersi, perché anche se lo volessi, non sai come. Il modo in cui respingi con disinvoltura una buona argomentazione come "lo stesso vecchio stanco terreno" ne è la prova. Non pensi di fondere come uno strumento; la pensi come un'eccezione o qualcosa di insolito. Qualcosa da mettere in discussione piuttosto che da usare.
Nicol Bolas,

9
@MasonWheeler: chi sei tu per decidere " stanno sbagliando "? Non si utilizzano DVCS, quindi non si ha esperienza con il flusso di lavoro DVCS. Non hai idea se sia utile o meno per i programmatori, in quanto non ne hai esperienza. Quindi quale autorità hai per dire che è "sbagliato" solo perché SVN non lo consente? È come dire che classi, funzioni virtuali e template sono sbagliati perché C non li ha.
Nicol Bolas,

3
@MasonWheeler: come questo? : P . La ramificazione e l'unione di SVN fanno la stessa cosa: la metafora è già rotta. Non vedo davvero come una cosa del genere sia così difficile da capire, soprattutto se include alcuni commenti di commit sensati ..
nought101

21

Non c'è niente di troppo difficile nella fusione di SVN ... più ... se segui la giusta filosofia

Quello che vedo nella maggior parte delle altre risposte sembra provenire da persone che non usano SVN da un po 'di tempo. Come qualcuno afferma con precisione: "non è stato risolto abbastanza presto per dissipare il mito".

Dalla mia attuale esperienza di utilizzo di SVN da 1.6 a 1.8 su un progetto legacy che ho ereditato di recente, SVN ha fatto molto per rendere la fusione molto più semplice. Tuttavia, non è infallibile e penso che non subisca facilmente utenti che si discostano dall'uso previsto.

Mentre conoscevo abbastanza bene SVN e nel frattempo avevo anche provato Mercurial per progetti personali, prima di questo progetto non avevo mai fatto molte ramificazioni in SVN. C'è stato un bel po 'di tentativi ed errori e ho avuto un sacco di conflitti di unione inaspettati quando ho iniziato.

Alla fine, però, mi sono reso conto che ogni volta che ho avuto uno (o qualche altro problema), era perché non avevo fatto le cose correttamente (aka "il modo SVN" - probabilmente, il modo corretto di controllo della versione). Credo che sia qui che sta la difficoltà: non puoi fare ciò che vuoi in modo non organizzato e aspettarti che SVN funzioni perfettamente, specialmente con le fusioni. Le fusioni richiedono una rigorosa disciplina da parte degli utenti prima che mostrino il loro vero potere.

Ecco alcune cose che ho notato sono forti raccomandazioni, se non requisiti, per un uso pulito delle fusioni:

  • Utilizzare una versione recente di SVN (1.6 e versioni successive a mio avviso). Sempre più automazioni e controlli sono fatti per te.
  • Usa la struttura predefinita "trunk, rami, tag" e applica la sua filosofia (non impegnarti nei tag). SVN non controlla nulla per te. Se usi un tag come ramo (è lo stato in cui ho trovato il repository del progetto), può ancora funzionare, ma devi essere coerente.
  • Scopri cosa sono i rami e quando crearli. Lo stesso con i tag.
  • Mantieni i rami laterali aggiornati con il loro ramo di origine (di solito tronco, ma puoi ramificarti tecnicamente da qualsiasi ramo). Questo è obbligatorio SE vuoi che SVN esegua le fusioni automatiche. SVN 1.8 in realtà ti impedisce di unirti automaticamente se le cose non sono aggiornate e anche se hai modifiche in sospeso nella tua copia di lavoro (questo comportamento sembra essere scomparso di nuovo in 1.8.5).
  • Fare commit "adeguati". Dovrebbero contenere solo modifiche su un concetto molto specifico. Per quanto possibile, dovrebbero contenere una piccola quantità di modifica. Ad esempio, non si desidera che un singolo commit contenga modifiche su due bug indipendenti. Se sono già stati corretti entrambi e si trovano nello stesso file, è necessario archiviare le modifiche di un bug in modo da poter eseguire solo il commit delle modifiche dell'altro, quindi il secondo set di modifiche. Si noti che TortoiseSVN lo consente facilmente tramite "Ripristina dopo il commit".
    • In questo modo è possibile ripristinare una specifica serie indipendente di modifiche E è possibile unire tale serie in un altro ramo. Sì, SVN ti consente di unire le revisioni selezionate dalla ciliegia.
  • Se usi mai i rami secondari (ramo fuori dal tronco, quindi ramo quel nuovo ramo), rispetta la gerarchia. Se aggiorni il ramo secondario con il tronco o viceversa, ti senti un po 'addolorato. Le fusioni dovrebbero essere messe in cascata verso il basso o verso l'alto nella gerarchia.
    • Dopo alcuni mesi di sperimentazione, posso garantire che questa potrebbe essere la parte più importante. Ho provato a creare due rami secondari dallo stesso tronco e quindi a unire i bit tra i rami secondari, o talvolta tra i rami secondari secondari da entrambi i lati. Questo può far scattare SVN (o l'utente). Può funzionare correttamente se si uniscono revisioni specifiche. L'unione automatica potrebbe avere dei problemi.
    • Ho avuto problemi in particolare durante la sincronizzazione del sotto-ramo A con il trunk e quindi cercando di unire qualcosa dal sotto-ramo A al sotto-ramo B. SVN sembra pensare che la revisione "Sincronizza dal trunk" dovrebbe legittimamente essere unita al sotto-ramo B e questo porta a una massa di conflitti.
  • Per quanto possibile, unisci dalla radice del ramo. In caso contrario, SVN ti terrà traccia delle unioni fatte per la sotto-cartella e quando si fanno tenta di auto-merge dalla radice, è possibile ottenere avvisi di perdere revisioni non uniti. È risolvibile semplicemente unendo questi dalla radice, ma meglio evitare la confusione.
  • Fai attenzione a quale ramo ti impegni. Se usi Switch per fare in modo che la tua copia di lavoro punti a varie filiali nel tempo, assicurati di dove ti impegni.
    • È particolarmente brutto se davvero non volevi il cambiamento in quel ramo. Non sono ancora chiaro su quello, ma a seconda di come ti sbarazzi di esso / trasferiscilo nel ramo giusto (ripristinando, fondendo), puoi ottenere qualcosa di disordinato. È risolvibile, ma dovrai unire la revisione per revisione per evitare o risolvere immediatamente potenziali conflitti, oppure dovrai correggere un conflitto forse più complesso dopo l'auto-fusione.
  • Non mantenere i rami intatti per troppo tempo. In realtà, non è una questione di tempo ma di quante revisioni sono state impegnate nel ramo e nel tronco e quanto sono cambiate in queste. Le fusioni tra due rami, le fusioni a 3 vie, vengono sempre confrontate con la revisione comune più recente tra i rami. Maggiore è il numero di modifiche nel mezzo, maggiore sarà il cambiamento della fusione automatica. Questo è, ovviamente, molto peggio se nel frattempo hai cambiato la struttura del tuo codice (file spostati o rinominati).

Se non segui quanto sopra, è molto probabile che si verifichino conflitti. Sono sempre risolvibili, ma non terribilmente divertenti per passare il tempo.

Oh, un'altra cosa sulla fusione in cui, da quanto ho letto e provato, SVN fa davvero schifo: file / cartelle cancellati / spostati / rinominati. Apparentemente , SVN non riesce ancora a gestire un file rinominato, cancellato o spostato in un ramo e la sua versione originale modificata in un altro ramo ... e quindi unendoli insieme. Semplicemente non saprà dove è andato il file in un modo e "dimenticherà" le modifiche nell'altro modo. Una modifica è ovviamente irrisolvibile (elimini o modifichi il file, non puoi fare entrambe le cose), ma l'applicazione delle modifiche ai file spostati / rinominati dovrebbe funzionare e non funziona. Spero che questo venga risolto presto.

Quindi, tutto sommato, la fusione SVN è facile? Non credo. Non in modo spensierato, di sicuro. È male ? Io non la penso così. Ti sputa in faccia solo quando lo usi nel modo sbagliato e non pensi abbastanza a quello che stai facendo.

Sulla base di questo, posso capire perché le persone potrebbero preferire Mercurial (ad esempio) in quanto è un po 'più indulgente su queste cose dalla mia esperienza e aveva tutto automatizzato fin dall'inizio (almeno dalle prime versioni con cui ho iniziato). SVN ha recuperato un bel po ', però, quindi non è più degno di così tanti colpi di grazia.


Conflitti degli alberi - sì, SVN ha difficoltà con questi, anche se TBH lo è anche con tutti gli altri SCM. Git ha alcune euristiche per cercare di capire se i file che sono stati rinominati o spostati sono gli stessi, ma non sempre (non è possibile!). Penso che SVN dovrebbe fare qualche sforzo per rendere più comprensibile la risoluzione di questi conflitti.
gbjbaanb,

@gbjbaanb: offre "Sposta di riparazione" come fa Mercurial, sebbene non offra euristica. Devi dirlo quali file eliminati e aggiunti sono, in effetti, gli stessi. Sicuramente margini di miglioramento.
leokhorn,

Tutto questo suona alla grande quando sei l'unica persona che lavora al progetto ... Ma se hai un team di buone dimensioni e lo usano tutti in "SVN way" (che nessuno sembra concordare esattamente di cosa si tratti) si fonde sono ancora un PITA. Il fatto è che svn non supporta molto bene il flusso di lavoro delle ramificazioni. Il "modo SVN" sarebbe quello di non creare nemmeno rami e usare un SDLC a cascata. Detto questo, ho avuto problemi con Git si fonde in passato su grandi progetti con diverse persone che ci lavorano. Ma sembravano ancora molto meno dolorosi.
Tokyo,

La mia esperienza è che se lavori con persone che non si preoccupano di come funziona il sistema di controllo della versione, SVN è molto più facile da usare su una base quotidiana. Ho lavorato solo su alcuni team DVCS ma invariabilmente un numero considerevole del team non ha un buon comportamento di controllo delle revisioni e inquina il repository per tutti. In Subversion, i non addestrati generalmente stanno alla larga dalle filiali in modo che gli "esperti" possano farlo per loro e sono gestiti in modo appropriato. Concesso, questa esperienza è solo mia e preferirei lavorare solo con programmatori che sapevano come funzionavano i loro strumenti ...
dash-tom-bang

5

I modelli di dati interni sono sostanzialmente diversi.

Fondamentalmente, in SVN, quando guardi la storia di un ramo, vedi solo cosa è successo in quel ramo. Pertanto, quando si unisce da un ramo Ball'altro A, la cronologia del ramo Aconterrà un commit di grandi dimensioni contenente tutte le modifiche apportate in modo esplicito da Bquando è stato ramificato.

Nelle prime versioni di SVN, se è stato necessario unire nuovamente il ramo Bnel ramo A, è stato necessario specificare manualmente l'intervallo di revisione del ramo che Bsi desidera unire per evitare di unire due volte le stesse revisioni. Lo sviluppatore intelligente userebbe ovviamente un messaggio di commit come "Fuso in B: 1234".

SVN 1.5 "risolto" questo. Ma non è cambiato il modo in cui le fusioni vengono applicate fondamentalmente. Ha semplicemente aggiunto alcuni metadati extra al ramo A, facendo sapere a SVN che la revisione 1234 era stata unita, consentendo a SVN di scegliere automaticamente l'intervallo di revisione corretto.

Ma questa soluzione è sostanzialmente una soluzione alternativa per un modello di dati che fondamentalmente non supporta la traccia di ciò che è stato unito.

L'unione di due rami è un esempio relativamente semplice. Ma immaginando questo scenario più complesso

  1. Crea filiale Ada trunke fai alcuni commit qui
  2. Crea filiale Bda Ae fai alcuni commit qui
  3. Fai qualche commit in trunkeA
  4. Unisci Bintrunk
  5. Unisci AinB
  6. Unisci Aintrunk
  7. Unisciti Ba trunk(questo non dovrebbe effettivamente fare nulla)

La gestione corretta utilizzando il modello di metadati diventa estremamente complessa (non so se SVN gestisce effettivamente correttamente questo scenario e non mi sento propenso a provarlo).

Gestire questo scenario in git è estremamente semplice.

In git, ogni volta che commetti, l'oggetto interno che rappresenta quel commit contiene un riferimento all'intestazione precedente. Quando si uniscono in un ramo, il commit contiene riferimenti all'intestazione precedente di tutti i rami che vengono uniti (in git è possibile unire più di un ramo alla volta)

Pertanto, quando si esamina la cronologia di un singolo commit in git, è possibile vedere tutta la cronologia, è possibile vedere quando è stata ramificata, quando è stata unita e si può vedere la cronologia di entrambi i rami tra la ramificazione e la fusione.

Pertanto, quando si esegue la fusione in una succursale che è stata parzialmente unita, è estremamente semplice determinare cosa è già stato unito e cosa no.

Non ho esperienza con Mercurial, ma sospetto che i suoi meccanismi interni siano simili a Git.

Fondamentalmente, per SVN, era un obiettivo di progettazione rendere la ramificazione economica. Ma in sostanza, era un obiettivo di progettazione rendere la fusione economica.

Infine, l'ultima volta che ho usato SVN, non è stato in grado di gestire le fusioni, in cui un file è stato rinominato in un ramo e modificato in un altro.


1

Ho fatto un bel po 'di fusione SVN, incluso lo sviluppo di lunga data e le filiali di rilascio. Nel complesso sono sopravvissuto. La fusione è sempre complicata, ma con DCVS il rovescio della medaglia non è orribilmente negativo: tutto è locale, quindi aggiorna a una buona revisione conosciuta e continua. Considerando che con SVN si è verificato molto sul lato server, quindi il recupero è stato brutto - di solito ha comportato l'eliminazione della copia locale, quindi il controllo di un nuovo ramo pulito per riprovare. Non è stato male nel mio caso - una connessione gigabit con la scatola SVN aiuta. Ma abbiamo avuto alcuni appaltatori che hanno avuto molti problemi con questo perché erano su connessioni lente, quindi tutto è durato per sempre, comprese le fusioni.


estrapolando la cosa della connessione lenta, lavorare da un server remoto fuori sede rende anche scarsi gli errori di connessione abbandonati quando si effettuano aggiornamenti di grandi dimensioni> <Non è affatto divertente.
jxramos,

-1

Sì, lo faccio anch'io. Al momento ho 12 VM per diverse versioni (rami) del progetto di cui faccio parte al lavoro. Quando devo correggere un bug in una versione precedente, correggo il bug, quindi unisco il commit nei rami per le versioni più recenti. Ma ora questo sta ricongiungendo un intero ramo, di cui sto parlando qui.

Qui sta una delle cose molto belle di Git. Non è eredità di DVCS, è solo qualcosa che git eccelle. È possibile unire revisioni specifiche da qualsiasi ramo in un altro ramo. Prende semplicemente il diff e lo applica all'altro ramo, ma fa il tracking ed è molto più automatico.

Pertanto, se si dispone del ramo 2.0 e del ramo 3.0 e si rileva un bug in 2.0, è quindi possibile risolverlo in 2.0 e prendere l'insieme di revisioni che lo risolvono e unire solo quelle revisioni nel ramo 3.0. Non credo che SVN abbia altro modo di farlo se non quello di prendere manualmente le differenze per ogni revisione e applicarle

Ovviamente, anche l'algoritmo di unione automatica sembra funzionare molto più agevolmente e git è stato creato da zero sul modello "crea un ramo per tutte le cose", quindi la ramificazione è semplicemente liscia e facile. Sembra naturale ramificarsi spesso con la sua leggerezza


Inoltre, immagino che mercurial abbia funzionalità simili
Earlz

2
In realtà, puoi fare esattamente la stessa cosa in SVN. Lo faccio tutto il tempo. Il comando Unisci SVN può estrarre una revisione (o un intervallo di revisioni) da un ramo diverso e applicarlo alla tua copia di lavoro, quindi esegui il commit.
Mason Wheeler

2
@MasonWheeler Tieni presente che gran parte del sentimento anti-svn era diretto alle versioni precedenti alla 1.5 (quando svn ha ottenuto il monitoraggio delle unioni). E ovviamente molto è solo un inutile fanboyismo ...
yannis,

3
@MasonWheeler puoi anche stackoverflow.com/a/4215199/69742 quel post si riduce a DVCS registra change-set non le versioni . I set di modifiche sono intrinsecamente facili da prendere e unire ... versioni non tanto perché richiedono contesto
Earlz,

@MasonWheeler oh e questo: stackoverflow.com/questions/2471606/...
Earlz
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.