Scegliere la giusta strategia di ramificazione per le versioni

11

Iniziando con un nuovo team di sviluppo su un nuovo progetto e dobbiamo definire la nostra strategia Branching per il nostro repository sorgente (, ad esempio Microsoft Team Foundation Server 2010 ). Ci siamo imbattuti in una discussione appiccicosa sull'opportunità o meno di ...

A . Avere un ramo Release da cui facciamo le build di produzione e poi Etichetta quando qualcosa viene effettivamente pubblicato

OR

B . Avere un nuovo ramo Release per ogni nuova versione in produzione ( Es. Versione 1, 2, 3, ecc ... )

L'opzione A sembra piuttosto semplice, ma non siamo sicuri che questo porterà a problemi nel lungo periodo. L'opzione B sembra creare solo un sacco di rami di una tantum che si accumulano nel tempo.

Qualcuno ha qualche esperienza in entrambi i casi che potrebbe aiutarci a decidere? In particolare, sto cercando di sentire dove sono i punti di dolore per ogni scelta. Sentiti libero di fornire un'esperienza specifica relativa alle implicazioni di TFS e / o Release-Management.

    
posta JoeGeeky 21.01.2012 - 13:01
fonte

6 risposte

15

Opzione A. Semplicemente usando la linea principale e taggando per il rilascio

Pro:

  •     Evita l'unione dell'inferno.
  •     Mantenere la linea principale incoraggia alcune best practice come la corretta pianificazione dei rilasci, non introducendo molti WIP, l'uso della ramificazione per astrazione per gestire il lavoro a lungo termine fuori banda e l'utilizzo del sistema open closed e delle funzionalità configurabili per gestire i lavori di gestione in corso che può; o non può; deve essere disabilitato ora o in futuro per rilasciare o evitare un rollback completo.

Contro:

  • Affrontare i lavori in corso diventa un problema e aggiunge alla potenziale superficie di attacco quando arriva il momento di rilasciare. Tuttavia, se gli sviluppatori sono disciplinati, le nuove funzionalità dovrebbero essere configurabili e modulari e quindi facilmente disabilitate / abilitate, oppure non vi è alcun WIP e in ogni punto di rilascio tutto il lavoro è completato o non ancora avviato (es. Scrum).
  • Le modifiche su larga scala / fuori banda richiedono più tempo prima di implementarle (ad esempio la ramificazione per astrazione).

Personalmente preferisco questo approccio. La copertura del codice e le unit test dovrebbero identificare il codice che non è pronto per uscire e le persone non dovrebbero lavorare su codice che non verrà rilasciato durante l'iterazione corrente. La ramificazione per astrazione o altri meccanismi può essere utilizzata per affrontare cambiamenti a lungo termine e lavori in corso.

Quando non lo fai, inizi a trovarti a gestire problemi di fusione, codice non aggiornato, funzionalità che non vengono mai rilasciate, ecc.

Opzione B. Ramo per versione

Pro:

  • Puoi iniziare a lavorare sulla prossima iterazione mentre l'iterazione corrente termina il suo round di test di accettazione.
  • Altre cose sono sicure.

Contro:

  •   
  • tonnellate di rami.   
  • Ancora bisogno di taggare i rami nei punti di rilascio.   
  • Ancora bisogno di trattare con WIP e unire WIP dal ramo di rilascio precedente nel ramo successivo della release, se non lo farà e sarà comunque necessario disabilitarlo o strattonarlo dal ramo di rilascio ed eseguire nuovamente i test di accettazione   
  • Le hot fix devono essere applicate a più rami (ramo di rilascio + hotfix + nuovo tag + unisci hotfix nel ramo vnext e possibilmente vnextnext a seconda di dove cade l'aggiornamento rapido).

Non sono un grande fan di questa soluzione ^ _ ^.

Generalmente raccomanderei solo di attenermi alla linea principale. Se i tuoi sviluppatori hanno problemi a non scrivere WIP che può essere facilmente strappato quando fallisce il taglio o che è stato controllato in anticipo per la prossima versione, puoi iniziare a parlare di tagging del codice nel punto in cui dovrebbe essere il codice completo e ramificato da lì se necessario per affrontare difetti e bug trascurati che i test unitari degli sviluppatori non sono riusciti a catturare.

Idealmente penso che tu voglia che sia il processo di eccezione, non la regola.

Opzione C. Opzione bonus pazzesco

Se vuoi divertirti, puoi anche prendere in considerazione un modello di ramificazione per story-story / per-feature. ( Un'idea terribile in TFS o in qualsiasi DVCS e allo stesso tempo incredibilmente semplice da implementare se si utilizza un DVCS come git o mercurial ).

In passato ho implementato il sotto per un precedente team di manutenzione dei datori di lavoro che lavorava con una base di codice legacy che non poteva essere facilmente trasferita su mercurial da svn. Un sacco di lavoro non necessario è stato coinvolto per soddisfare un requisito aziendale di una linea principale sempre rilasciabile piuttosto che coordinare meglio le pubblicazioni ma. . .

  1. Le funzionalità sono state sviluppate dagli sviluppatori nel loro ramo dedicato ai team.
  2. Quando una funzione è pronta per essere sottoposta a peer review, gli sviluppatori lo raggruppano in un'unica unione dal ramo Dev al ramo CR e includono l'ID funzione / storia utente nel titolo. * Applicato dal gancio di pre-commit *
  3. Una volta superato CR, viene utilizzato uno strumento di amministrazione per promuovere la funzione nel ramo QA. (Ho scritto una piccola applicazione terminale che elencava le storie degli utenti presenti nelle varie fasi di accettazione e ha permesso all'operatore di promuoverle o dimezzarle tra quelle fasi di accettazione)
  4. QA esegue test di automazione e test di usabilità manuali. Se la funzionalità è buona, viene inserita nel ramo di rilascio (linea principale). Se la funzione viene rifiutata, viene declassata / ripristinata dal ramo QA fino a quando gli sviluppatori non sono in grado di risolvere i problemi sollevati durante il test e aggiungere inviare una patch al ramo CR.
  5. Se il codice è stato ripristinato dal ramo QA e viene applicata una correzione, lo strumento terminale riapplicherà le modifiche necessarie per riportare la funzionalità sulla branca QA dal ramo CR in modo che il controllo qualità possa riesaminare il codice e promuoverlo o retrocederlo di nuovo.
  6. In qualsiasi momento, il ramo di rilascio dovrebbe trovarsi in uno stato rilasciabile stabile.
  7. Dopo un rilascio, Dev, QA e CR vengono convertiti dalla linea principale.
risposta data 21.01.2012 - 14:45
fonte
6

Abbiamo filiali distinte per ogni versione distribuita (circa 4 all'anno). È molto comodo quando devi scaricare una versione specifica.

Se hai bisogno di mantenere un paio di versioni precedenti, non penso che l'etichettatura potrebbe fare. Con rami di rilascio specifici, puoi applicare hot-fix a ciascun ramo separatamente (o ad una selezione di essi) senza preoccuparti di nessuno degli altri rilasci.

Inoltre rende molto più facile il confronto tra rilasci quando cerchi quando sono stati introdotti bug o funzionalità.

Non preoccuparti del numero di filiali o del tempo trascorso senza modifiche. Il tuo sistema di controllo delle versioni ti consente di controllare e fornire una cronologia dello sviluppo del tuo progetto. La storia ha la tendenza a non cambiare ... E non preoccuparti che i tuoi CV non siano in grado di farcela. Utilizziamo Perforce, 9000+ file in un ramo di sviluppo, fino a 50 rami di sviluppo per le versioni a cui stiamo lavorando e, come già detto, un singolo ramo per versione che pubblichiamo. Perforce non respira nemmeno di più.

In breve: rendi la vita più facile come sviluppatore / manutentore / bug-fixer / problem-hunter e non preoccuparti del numero di filiali o del numero di file. Cvs che si rispetti.

Modifica

Non abbiamo alcuna confusione riguardo al numero di filiali che abbiamo. Il nostro schema di denominazione per i rami di rilascio e la nostra politica di ramo 1 di emissione per i rami di sviluppo (o di lavoro) potrebbe avere qualcosa a che fare con questo.

I rami di rilascio sono denominati per il rilascio in loro possesso, vale a dire: R2011SP1 per Service Pack 1 Release 1. I nostri rami di lavoro hanno nomi meno intelligenti: sub01, sub02, sub03 ecc. Il "sub" deriva dal fatto che tutti i rami di lavoro sono succursali del ramo accettazione. Il ramo accettazione è quello in cui sono raccolti tutti i problemi che sono pronti per essere rilasciati.

La nostra politica sulle filiali di lavoro 1 problema 1, combinata con il fatto che il nostro sistema di tracciamento dei problemi è stato personalizzato con un campo "succursale" ci assicura che sappiamo sempre quale problema è stato sviluppato in quale ramo. Quando un problema è integrato nel ramo accettazione, questo campo viene aggiornato. Ciò significa che sappiamo sempre quali problemi sono pronti per il rilascio (una volta eseguito il test di accettazione). Allo stesso modo aggiorniamo questo campo quando viene creato un ramo di rilascio e in questo modo possiamo sempre rintracciare in quale rilascio è stato rilasciato un problema.

    
risposta data 21.01.2012 - 14:06
fonte
2

Riguarda il contesto: ogni quanto tempo rilasci e cosa c'è in una versione.

Ecco un po 'di case study che ho avuto con il mio vecchio lavoro, utilizzando il metodo B (l'abbiamo chiamato branch by purpose ).

Per mettere la storia in un contesto,

  • Una versione consisteva in nuove funzionalità nel nostro software: nuove modalità di gioco, nuove funzionalità, nuove opzioni di configurazione.
  • Il ciclo di rilascio è stato piuttosto lungo: i nostri clienti erano università che si sarebbero limitate a un set di funzionalità solitamente per un anno.

Lo sviluppo principale è stato effettuato nel bagagliaio fino a quando non abbiamo raggiunto lo stato di completamento di una determinata release. A quel punto creeremo un ramo, diciamo projectname-january2012 e eseguiremo test di qualità e correzioni di bug in quel ramo. Una volta che eravamo pronti per una versione pubblica, dovremmo codificare il codice in quel ramo e rilasciare.

Tuttavia, lo sviluppo della versione non si è concluso con quel tag. Inevitabilmente, abbiamo avuto clienti che hanno trovato bug o piccoli problemi con il rilascio. In tal caso, tutto ciò che dobbiamo fare è tornare a quel ramo, applicare patch al codice e creare una nuova versione taggata del ramo january2012 da rilasciare, e unire le correzioni al tronco .

Nel nostro caso, questo approccio era favorevole perché alcuni utenti preferivano rimanere con versioni precedenti con una serie limitata di funzionalità, o semplicemente perché il costo di distribuire sull'infrastruttura una nuova versione piuttosto che una correzione causava alcuni problemi.

Quindi le domande che devi porsi sono:

  • Quanto spesso rilascio?
  • Le mie versioni saranno compatibili al 100% con versioni precedenti?
  • I miei clienti staranno bene aggiornando completamente per correggere i bug?

Se rilasci spesso, allora forse non vale la pena avere rami per ognuno di essi. Tuttavia, se il tuo ciclo di rilascio è abbastanza lungo come il mio vecchio caso d'uso, e tale implementazione, compatibilità con le versioni precedenti e client aggrappati a vecchie versioni potrebbero essere rischi, l'opzione B ti farà sicuramente risparmiare molto rendere le cose molto più semplici per supportare i tuoi clienti al minimo costo di gestire il disordine dei rami.

    
risposta data 21.01.2012 - 16:42
fonte
1

Preferisco l'opzione A. Sviluppa sul tronco e sui lanci quando sono stabili. Ciò limita significativamente il lavoro di integrazione degli hot fix applicati alla versione di produzione.

Sono stato contattato per aiutare una squadra che ha tentato l'opzione B a tornare in pista.

Alcune cose da considerare.

  • Migrare gli hotfix in avanti attraverso tutti i rami di codice attivi. Questo può essere fatto unendo, patch e / o riqualificazione. Questi dovrebbero essere completamente gestiti per garantire che una correzione venga applicata a tutte le versioni appropriate, quindi al trunk.
  • Considerare i rami di funzionalità per abilitare lo sviluppo di funzionalità isolate dal flusso di codice principale. Questi sono consigliati per i cambiamenti sperimentali. Sentiti libero di abbandonare i rami delle funzionalità se la funzione non funziona.
  • Tagga e traccia i tuoi punti fusione.
  • Separa le tue pubblicazioni quando richiesto. Trovo che questo è normale quando la versione è pronta per le build candidate. In alcuni casi, l'introduzione di modifiche incompatibili al trunk potrebbe forzare e anticipare il ramo. Si consideri un ramo di funzionalità.
risposta data 22.01.2012 - 01:33
fonte
0

Ho lavorato per un certo numero di anni su un sistema che usa qualcosa in qualche modo tra i due schemi che descrivi. La chiave è che c'è uno schema di numerazione multilivello in uso. Il livello esterno è fondamentalmente la versione dell'API e viene gestito sui rami (con cross-merges appropriati quando qualcosa deve essere corretto su più rami) e il livello interno è il rilascio esatto eseguito, che viene gestito con i tag.

In particolare, se conosciamo la versione esatta di un cliente, sappiamo esattamente da quale fonte è stato creato il codice e possiamo creare un duplicato esatto in modo che possiamo vedere esattamente cosa sta succedendo. Questo è molto importante per il supporto! Eppure il livello esterno delle filiali, le versioni API che rilasciamo attualmente, si evolvono nel tempo (con il principale tronco di sviluppo che ottiene la maggior parte delle nuove funzionalità). Inoltre, quando realizziamo una nuova versione principale dell'API, facciamo una nuova filiale per supportarla (in modo che il trunk possa sempre essere orientato allo sviluppo hard-core) e consideriamo se dobbiamo terminare la vita del supporto più vecchio corrente ramo.

Perciò raccomando qualcosa che sia davvero una combinazione di entrambi A e B ; entrambi hanno aspetti positivi, ma nessuno dei due è completo in sé. Usa il meglio di entrambi i mondi.

    
risposta data 22.01.2012 - 17:14
fonte
0

Ho usato TFS per implementare in modo efficace l'opzione (B) in passato.

Branching / merging è un ottimo strumento quando è fatto in piccoli pezzi. La difficoltà non sta nel fare un ramo (che è stupido facile), né spingere indietro un valore di una settimana di lavoro sull'albero (che di solito è anche facile) ... è nel far sì che il sistema di CI dietro il controllo del codice sorgente lavori automaticamente te.

Perché la ramificazione è discutibile se il sistema non crea automaticamente e esegue test per il ramo.

Abbiamo personalizzato il flusso di lavoro di generazione predefinito di TFS per riconoscere i percorsi relativi dei changeset e stabilito una convenzione in base alla quale la personalizzazione poteva riconoscere un nuovo ramo (diversamente da una nuova sottocartella in alcune root di sviluppo). E 'stato semplice, facile da ramificare, facile da uccidere un ramo, e abbiamo ricevuto un feedback continuo dal nostro sistema per la compilazione e i test.

Vedo un sacco di persone che dichiarano quanto queste strategie siano impossibili sotto TFS e credo che ciò sia dovuto alla mancanza di familiarità con le possibilità di un motore di compilazione basato su XAML. TFS non è solo il controllo del codice sorgente, è una soluzione completa e dovrebbe essere utilizzato come tale.

    
risposta data 31.08.2016 - 16:45
fonte