Domanda

Supponiamo che tu stia sviluppando un prodotto software con versioni periodiche.Quali sono le migliori pratiche per quanto riguarda la ramificazione e la fusione?Tagliare i rami di rilascio periodico al pubblico (o chiunque sia il tuo cliente) e poi continuare lo sviluppo sul tronco, o considerare il tronco come la versione stabile, etichettarlo periodicamente come rilascio e fare il lavoro sperimentale nei rami.Cosa pensa la gente se il baule sia considerato "d'oro" o considerato una "scatola di sabbia"?

È stato utile?

Soluzione

Ho provato entrambi i metodi con una grande applicazione commerciale.

La risposta a quale sia il metodo migliore dipende fortemente dalla tua situazione esatta, ma scriverò ciò che la mia esperienza complessiva ha mostrato finora.

Il metodo migliore in generale (secondo la mia esperienza):Il tronco dovrebbe essere sempre stabile.

Ecco alcune linee guida e vantaggi di questo metodo:

  • Codifica ogni attività (o insieme di attività correlate) nel proprio ramo, quindi avrai la flessibilità di quando desideri unire queste attività ed eseguire un rilascio.
  • Il QA dovrebbe essere eseguito su ciascun ramo prima che venga unito al trunk.
  • Eseguendo il QA su ogni singolo ramo, saprai esattamente cosa ha causato il bug più facilmente.
  • Questa soluzione è adattabile a qualsiasi numero di sviluppatori.
  • Questo metodo funziona poiché la ramificazione è un'operazione quasi istantanea in SVN.
  • Tagga ogni versione che esegui.
  • Puoi sviluppare funzionalità che non prevedi di rilasciare per un po' e decidere esattamente quando unirle.
  • Per tutto il lavoro che svolgi, puoi avere il vantaggio di impegnare il tuo codice.Se lavori solo fuori dal trunk, probabilmente manterrai il tuo codice per molto tempo senza impegno, e quindi non protetto e senza cronologia automatica.

Se provi a fare il contrario e fai tutto lo sviluppo nel bagagliaio, avrai i seguenti problemi:

  • Problemi di build costanti per le build quotidiane
  • Perdita di produttività quando uno sviluppatore commette un problema per tutte le altre persone nel progetto
  • Cicli di rilascio più lunghi, perché è necessario ottenere finalmente una versione stabile
  • Versioni meno stabili

Semplicemente non avrai la flessibilità di cui hai bisogno se provi a mantenere stabile un ramo e il tronco come sandbox di sviluppo.Il motivo è che non puoi scegliere dal bagagliaio cosa vuoi inserire in quella versione stabile.Sarebbe già tutto mescolato insieme nel bagagliaio.

L'unico caso in particolare in cui direi di eseguire tutto lo sviluppo nel bagagliaio è quando si avvia un nuovo progetto.Potrebbero esserci anche altri casi a seconda della situazione.


A proposito, i sistemi di controllo della versione distribuiti offrono molta più flessibilità e consiglio vivamente di passare a hg o git.

Altri suggerimenti

Ho lavorato con entrambe le tecniche e direi che sviluppare sul tronco e diramare punti stabili come versioni è la strada migliore da percorrere.

Quelle persone sopra che obiettano dicendo che avrai:

  • Problemi di build costanti per le build quotidiane
  • Perdita di produttività quando lo sviluppatore AA commette un problema per tutte le altre persone nel progetto

probabilmente non hanno utilizzato tecniche di integrazione continua.

È vero che se non si eseguono diverse build di test durante il giorno, diciamo una volta ogni ora circa, si esporranno a questi problemi che strangoleranno rapidamente il ritmo dello sviluppo.

L'esecuzione di diverse build di test durante il giorno inserisce rapidamente gli aggiornamenti al codice base principale in modo che altri possano usarlo e ti avvisa anche durante il giorno se qualcuno ha danneggiato la build in modo che possano ripararlo prima di tornare a casa.

Come sottolineato, scoprire una build danneggiata solo quando la build notturna per l'esecuzione dei test di regressione fallisce è pura follia e rallenterà rapidamente le cose.

Leggi l'articolo di Martin Fowler su Integrazione continua.Abbiamo implementato il nostro sistema di questo tipo per un grande progetto (3.000 kSLOC) in circa 2.000 linee di Posix sh.

Tendo ad adottare l'approccio "ramo di rilascio".Il tronco è volatile.Una volta che il momento del rilascio si avvicina, creerei un ramo di rilascio, che tratterei con più cautela.Una volta terminato, etichetterò/taggherò lo stato del repository in modo da conoscere la versione rilasciata "ufficiale".

Capisco che ci siano altri modi per farlo: questo è proprio il modo in cui l'ho fatto in passato.

Entrambi.

Il tronco viene utilizzato per la maggior parte dello sviluppo.Ma si prevede che verranno compiuti i migliori sforzi per garantire che qualsiasi check-in nel bagagliaio non lo rompa.(parzialmente verificato da un sistema automatizzato di creazione e test)

Le versioni vengono mantenute nella propria directory, su di esse vengono apportate solo correzioni di bug (e quindi unite nel trunk).

Qualsiasi nuova funzionalità che lascerà il trunk in uno stato instabile o non funzionante viene eseguita in un ramo separato e quindi unita al trunk una volta completata.

Mi piace e utilizzo l'approccio descritto da Henrik Kniberg in Controllo della versione per più team agili.Henrik ha fatto un ottimo lavoro nello spiegare come gestire il controllo della versione in un ambiente agile con più team (funziona anche per team singoli in ambienti tradizionali) e non ha senso parafrasarlo, quindi pubblicherò semplicemente il "cheat sheet" (che si spiega da sé) di seguito:

alt text alt text

Mi piace perché:

  • È semplice:puoi capirlo dalla foto.
  • Funziona (e si ridimensiona) bene senza troppi problemi di fusione e conflitto.
  • Puoi rilasciare "software funzionante" in qualsiasi momento (nello spirito agile).

E nel caso non fosse abbastanza esplicito:lo sviluppo viene eseguito in "ramo(i) di lavoro", il trunk viene utilizzato per il codice DONE (rilasciabile).Controllo Controllo della versione per più team agili per tutti i dettagli

Un buon riferimento su un processo di sviluppo che mantenga stabile il trunk e svolga tutto il lavoro nei rami è quello di Divmod Sistema di sviluppo della qualità definitivo.Un breve riepilogo:

  • A tutto il lavoro svolto deve essere associato un ticket
  • Viene creato un nuovo ramo per ogni ticket in cui viene svolto il lavoro per quel ticket
  • Le modifiche provenienti da quel ramo non vengono riunite nuovamente nel trunk della linea principale senza essere riviste da un altro membro del progetto

Usano SVN per questo, ma ciò potrebbe essere fatto facilmente con qualsiasi sistema di controllo della versione distribuito.

Penso che il tuo secondo approccio (ad esempio contrassegnare le versioni e fare cose sperimentali nei rami, considerando il trunk stabile) sia l'approccio migliore.

Dovrebbe essere chiaro che i rami ereditano tutti i bug di un sistema nel momento in cui viene ramificato:se le correzioni vengono applicate a un trunk, dovrai passare uno per uno a tutti i rami se mantieni i rami come una sorta di terminatore del ciclo di rilascio.Se hai già avuto 20 rilasci e hai scoperto un bug che risale al primo, dovrai riapplicare la correzione 20 volte.

I rami dovrebbero essere delle vere e proprie sabbiere, anche se anche il tronco dovrà svolgere questo ruolo:i tag indicheranno se il codice è "gold" in quel momento, adatto per il rilascio.

Sviluppiamo sul trunk a meno che i cambiamenti non siano troppo importanti, destabilizzanti, o ci stiamo avvicinando a una major release di uno dei nostri prodotti, nel qual caso creiamo un branch temporaneo.Creiamo inoltre una filiale permanente per ogni singola versione del prodotto.Ho trovato il documento di Microsoft su Guida alla ramificazione abbastanza utile.Eric Sink tutorial sulla ramificazione è anche interessante e sottolinea che ciò che funziona per Microsoft potrebbe essere troppo pesante per alcuni di noi.Nel nostro caso abbiamo effettivamente utilizzato l'approccio che Eric dice del suo team.

Dipende dalle tue situazioni.Utilizziamo Perforce e in genere abbiamo diverse linee di sviluppo.Il tronco è considerato "d'oro" e tutto lo sviluppo avviene sui rami che si uniscono alla linea principale quando sono sufficientemente stabili da integrarsi.Ciò consente di rifiutare le funzionalità che non riescono a raggiungere il traguardo e può fornire una solida capacità incrementale nel tempo che progetti/funzionalità indipendenti possono acquisire.

C'è un costo di integrazione per la fusione e il recupero delle nuove funzionalità introdotte nel bagagliaio, ma soffrirai comunque questo dolore.Far sì che tutti si sviluppino insieme sul tronco può portare a una situazione da selvaggio west, mentre la ramificazione ti consente di scalare e scegliere i punti in cui vorresti prendere le amare pillole di integrazione.Al momento disponiamo di oltre un centinaio di sviluppatori su una dozzina di progetti, ciascuno con più versioni che utilizzano gli stessi componenti principali, e funziona abbastanza bene.

La bellezza di questo è che puoi farlo in modo ricorsivo:un ramo importante può essere il proprio tronco con altri rami che si staccano.Inoltre, le versioni finali ottengono un nuovo ramo per darti un posto dove eseguire la manutenzione stabile.

Tentare di gestire la manutenzione dell'attuale codice di produzione in linea con il nuovo sviluppo è, nella migliore delle ipotesi, problematico.Per mitigare questi problemi, il codice dovrebbe diramarsi in una linea di manutenzione una volta completati i test e il codice è pronto per la consegna.Inoltre, la linea principale dovrebbe ramificarsi per assistere nella stabilizzazione del rilascio, per contenere gli sforzi di sviluppo sperimentale o per ospitare eventuali sforzi di sviluppo il cui ciclo di vita si estende su più rilasci.

Un ramo non di manutenzione dovrebbe essere creato solo quando esiste la probabilità (o la certezza) di collisioni tra il codice che sarebbero difficili da gestire in altro modo.Se la filiale non risolve un problema logistico, ne creerà uno.

Lo sviluppo normale del rilascio avviene nella linea principale.Gli sviluppatori entrano ed escono dalla linea principale per il normale lavoro di rilascio.Il lavoro di sviluppo per le patch dell'attuale codice di produzione dovrebbe essere nel ramo per quella versione e quindi fuso con la linea principale una volta che la patch ha superato i test e viene distribuita.Il lavoro nei settori non legati alla manutenzione dovrebbe essere coordinato caso per caso.

Dipende dall'entità del tuo sforzo di sviluppo.Più team che lavorano in parallelo non saranno in grado di lavorare in modo efficace tutti sullo stesso codice (trunk).Se hai solo un piccolo gruppo di persone che lavorano e la tua preoccupazione principale è tagliare un ramo in modo da poter continuare a lavorare mentre torni al ramo per apportare correzioni di bug al codice di produzione corrente che funzionerebbe.Questo è un uso banale della ramificazione e non troppo gravoso.

Se hai molto sviluppo parallelo, vorrai avere rami per ciascuno degli sforzi, ma ciò richiederà anche più disciplina:Assicurati che i tuoi rami siano testati e pronti per essere riuniti.La pianificazione delle fusioni in modo che due gruppi non tentino di unirsi contemporaneamente, ecc.

Alcuni rami sono in fase di sviluppo da così tanto tempo che è necessario consentire le fusioni da tronco a ramo per ridurre il numero di sorprese quando si ritorna infine al tronco.

Dovrai sperimentare se hai un gruppo numeroso di sviluppatori e avere un'idea di ciò che funziona nella tua situazione.Ecco una pagina di Microsoft che potrebbe essere alquanto utile: http://msdn.microsoft.com/en-us/library/aa730834(VS.80).aspx

Utilizziamo il trunk per lo sviluppo principale e il branch per i lavori di manutenzione delle release.Funziona bene.Ma poi i rami dovrebbero essere usati solo per correzioni di bug, senza modifiche importanti, specialmente sul lato database, abbiamo una regola secondo cui solo un cambiamento di schema può avvenire sul trunk principale e mai nel ramo.

Se lavorerai attraverso un ciclo di rilascio, una grande funzionalità, verrai abbandonato in un ramo.Altrimenti lavoriamo in trunk e branch per ogni versione di produzione nel momento in cui costruiamo.

Le build di produzione precedenti vengono spostate in quel momento in old_production_ e la versione corrente del prodotto è sempre solo produzione.Tutto ciò che il nostro server di build sa sulla produzione è come distribuire il ramo di produzione e diamo il via alla creazione con un trigger di forza.

Seguiamo l'approccio trunk=flusso di sviluppo corrente, branch=release(s).Al momento del rilascio al cliente ramifichiamo il tronco e lo manteniamo semplicemente ruotato in avanti.Dovrai prendere una decisione su quante versioni sei disposto a supportare.Più supporti, maggiore sarà la fusione che farai per le correzioni dei bug.Cerchiamo di mantenere i nostri clienti su non più di 2 sganciamenti dietro il bagagliaio.(Per esempio.Dev = 1.3, versioni supportate 1.2 e 1.1).

Il tronco è generalmente la principale linea di sviluppo.

Le versioni sono ramificate e spesso viene svolto un lavoro sperimentale o importante sui rami, quindi riuniti nel tronco quando è pronto per essere integrato con la linea di sviluppo principale.

Il trunk dovrebbe generalmente essere la tua principale fonte di sviluppo.Altrimenti passerai molto tempo a unire nuove funzionalità.Ho visto fare il contrario e di solito porta a molti grattacapi di integrazione dell'ultimo minuto.

Etichettiamo le nostre versioni in modo da poter rispondere rapidamente alle emergenze di produzione senza distribuire lo sviluppo attivo.

Per me dipende dal software che utilizzo.

Sotto CVS, lavoravo semplicemente in "trunk" e non taggavo/diramavo mai, perché era davvero doloroso fare diversamente.

In SVN, farei le mie cose "bleeding edge" nel trunk, ma quando era il momento di eseguire un push del server venivo taggato in modo appropriato.

Recentemente sono passato a Git.Ora scopro che non lavoro mai in tronco.Utilizzo invece un ramo sandbox denominato "new-featurename" e poi lo unisco in un ramo fisso "current-production".Ora che ci penso, dovrei davvero creare rami "release-VERSIONNUMBER" prima di unirli nuovamente a "current-production" in modo da poter tornare alle versioni stabili precedenti...

Dipende davvero da quanto bene la tua organizzazione/team gestisce le versioni e da quale SCM utilizzi.

  • Se ciò che verrà dopo (nella prossima versione) può essere facilmente pianificato, è meglio sviluppare nel bagagliaio.La gestione delle filiali richiede più tempo e risorse.Ma se il prossimo non può essere pianificato facilmente (succede sempre nelle organizzazioni più grandi), probabilmente finiresti per scegliere i commit (centinaia/migliaia) piuttosto che i rami (diversi o decine).
  • Con Git o Mercurial, gestire i branch è molto più semplice rispetto a cvs e subversion.Io opterei per la metodologia del tronco stabile/rami di argomenti.Questo è ciò che utilizza il team git.git.Leggere:http://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html
  • Con Subversion ho applicato per la prima volta la metodologia di sviluppo in-the-trunk.C'è stato un bel po' di lavoro per quanto riguarda la data di rilascio perché ogni volta dovevo scegliere i commit (la mia azienda non è brava nella pianificazione).Ora sono una specie di esperto in Subversion e conosco abbastanza bene la gestione dei rami in Subversion, quindi mi sto muovendo verso la metodologia stabile del tronco/rami degli argomenti.Funziona molto meglio di prima.Ora sto provando il modo in cui funziona il team git.git, anche se probabilmente resteremo fedeli a Subversion.

Ecco il design SVN che preferisco:

  • radice
    • sviluppo
      • rami
        • caratteristica1
        • caratteristica2
        • ...
      • tronco
    • beta
      • tag
      • tronco
    • pubblicazione
      • tag
      • tronco

Tutto il lavoro viene svolto da development/trunk, ad eccezione delle funzionalità principali che richiedono un proprio ramo.Dopo che il lavoro è stato testato rispetto a sviluppo/trunk, uniamo i problemi testati in beta/trunk.Se necessario, il codice viene testato rispetto al server beta.Quando siamo pronti per implementare alcune modifiche, uniamo semplicemente le revisioni appropriate nel rilascio/trunk e le distribuiamo.

I tag possono essere creati nel ramo beta o nel ramo di rilascio in modo da poter tenere traccia del rilascio specifico sia per la beta che per il rilascio.

Questo design consente molta flessibilità.Inoltre, ci rende più semplice lasciare le revisioni in beta/trunk mentre ne uniamo altre nella release/trunk se alcune revisioni non hanno superato i test in beta.

Il metodo che utilizziamo è l'approccio Perforce, di cui si parla a lungo nel bellissimo libro di Laura Wingerd:

http://oreilly.com/catalog/9780596101855/index.html

Sebbene il libro sia incentrato su Perforce (Wingerd è un product manager di Perforce), i concetti possono essere applicati a uno o tutti i VCS.

L'approccio (e la piattaforma) Perforce ci è stato molto utile.Viene utilizzato in molte aziende (Google, Intuit e, ho sentito, lo stesso Microsoft Windows).

Il libro merita di essere letto.

Non esiste una risposta valida per tutti alla domanda sulla convenzione di sovversione, IMHO.

Dipende davvero dalle dinamiche del progetto e dall'azienda che lo utilizza.In un ambiente molto frenetico, quando un rilascio potrebbe avvenire anche ogni pochi giorni, se provi a taggare e ramificare religiosamente, ti ritroverai con un repository ingestibile.In un ambiente di questo tipo, l'approccio "diramazione quando necessario" creerebbe un ambiente molto più gestibile.

Inoltre, nella mia esperienza è estremamente semplice, da un punto di vista puramente amministrativo, passare da una metodologia svn all'altra quando lo si desidera.

I due approcci che so che funzionano meglio sono il ramo quando necessario e il ramo per ogni attività.Questi sono, ovviamente, l'esatto opposto l'uno dell'altro.Come ho detto, è tutta una questione di dinamiche del progetto.

@Brian R.Bondy:Tieni presente che questa non è una soluzione una volta che il tuo team raggiunge un certo numero di persone/attività gestite in parallelo nel progetto.

Una volta che un reparto QA è coinvolto nel controllo qualità, gli sforzi necessari per fornire un'installazione per filiale in corso sono semplicemente troppo elevati.Pensare SOA/client/server/servizi Web/database tutto ciò deve essere fornito per ramo.

In questa soluzione manca anche la fase di integrazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top