Scegliere la giusta strategia di ramificazione per le versioni


11

A partire da un nuovo team di sviluppo su un nuovo progetto e dobbiamo definire la nostra strategia di Branching per il nostro repository di origine ( ad esempio Microsoft Team Foundation Server 2010 ). Abbiamo avuto una discussione appiccicosa sull'opportunità o meno di ...

A . Avere un ramo di rilascio da cui eseguiamo build di produzione e quindi Etichetta quando qualcosa viene effettivamente rilasciato

O

B . Avere un nuovo ramo di rilascio per ogni nuovo rilascio in produzione ( es. Versione 1, 2, 3, ecc ... )

L'opzione A sembra piuttosto semplice ma non siamo sicuri se questo porterà a problemi a lungo termine. L'opzione B sembra creare solo molti rami di lunga durata che si accumulano nel tempo.

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

Risposte:


15

Opzione A. Basta usare mainline e tagging per il rilascio

Professionisti:

  • Eviti di unire l'inferno.
  • Mantenere la linea principale incoraggia alcune buone pratiche come una corretta pianificazione delle versioni, non introdurre molto WIP, utilizzare la ramificazione per astrazione per gestire il lavoro a lungo termine fuori banda e utilizzare il sistema aperto chiuso e funzionalità configurabili per gestire la gestione delle opere in corso che può; o no; devono essere disabilitati ora o in futuro per rilasciare o evitare un rollback completo.

Contro:

  • Affrontare i lavori in corso diventa un problema e si aggiunge alla potenziale area di attacco di superficie quando arriva il momento del rilascio. Tuttavia, se i tuoi sviluppatori sono disciplinati, le nuove funzionalità dovrebbero essere configurabili e modulari e quindi facilmente disabilitate / abilitate, oppure non esiste un WIP e ad ogni punto di rilascio tutto il lavoro è completato o non è ancora stato avviato (cioè Scrum).
  • I cambiamenti su larga scala / fuori banda richiedono più tempo per implementare (ad es. Ramificazioni per astrazione).

Personalmente preferisco questo approccio. La copertura del codice e i test unitari dovrebbero identificare il codice che non è pronto per uscire e le persone non dovrebbero lavorare su codice che non verrà rilasciato durante l'attuale iterazione. 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 dover affrontare problemi di unione, codice non aggiornato, funzionalità che non vengono mai rilasciate, ecc.

Opzione B. Diramazione per rilascio

Professionisti:

  • Puoi iniziare a lavorare alla successiva iterazione mentre l'attuale iterazione termina il suo ciclo di test di accettazione.
  • Altre cose sono sicuro.

Contro:

  • Tonnellate di rami.
  • Devo ancora taggare i rami nei punti di rilascio.
  • È ancora necessario gestire WIP e unire WIP dal ramo di rilascio precedente nel ramo di rilascio successivo se non lo farà e dovrà comunque disabilitarlo o strapparlo dal ramo di rilascio e rieseguire i test di accettazione
  • Le correzioni rapide devono essere applicate a più rami (rilasciare ramo + hotfix + nuovo tag + unire hotfix nel ramo vnext e possibilmente vnextnext a seconda della posizione dell'aggiornamento rapido).

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

In generale, consiglierei di provare solo ad 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 è verificato in anticipo per la prossima versione, allora puoi iniziare a parlare di taggare il codice nel punto in cui dovrebbe essere completo e ramificato da lì, se necessario, per correggere difetti e bug trascurati che i test delle unità degli sviluppatori non sono riusciti a rilevare.

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

Opzione C. Opzione bonus pazzesca

Se vuoi divertirti, puoi anche prendere in considerazione un modello di ramificazione per storia utente / per caratteristica. ( Un'idea terribile in TFS o qualsiasi altro DVCS ma allo stesso tempo incredibilmente banale da implementare se si utilizza un DVCS come git o mercurial ).

In passato ho implementato il seguito per un precedente team di manutenzione dei datori di lavoro che ha lavorato con una base di codice legacy che non poteva essere facilmente trasferita su mercurial da svn. È stato necessario un sacco di lavoro non necessario per soddisfare le esigenze aziendali di una linea principale sempre rilasciabile piuttosto che coordinare meglio le pubblicazioni. . .

  1. Le funzionalità sono state sviluppate dagli sviluppatori nel ramo di sviluppo dei loro team.
  2. Quando una funzione è pronta per essere sottoposta a peer review, gli sviluppatori la raggruppano insieme in un'unica fusione dal ramo Dev al ramo CR e includono l'ID funzione / la storia utente nel titolo. * Applicato dall'hook pre-commit *
  3. Dopo aver superato CR, viene utilizzato uno strumento di amministrazione per promuovere la funzionalità nel ramo QA. (Ho scritto una piccola applicazione terminale che elenca le storie degli utenti presenti nelle varie fasi di accettazione e ha permesso all'operatore di promuoverle o degradarle tra quelle fasi di accettazione)
  4. Il controllo qualità esegue test di automazione e usabilità manuali. Se la funzionalità è valida, viene inserita nel ramo di rilascio (linea principale). Se la funzionalità viene rifiutata, viene ridotta / ripristinata dal ramo QA fino a quando gli sviluppatori non possono 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 applicherà nuovamente le modifiche necessarie per riportare la funzione sul ramo QA dal ramo CR in modo che il QA possa riesaminare il codice e promuoverlo o ridimensionalo di nuovo.
  6. In qualsiasi momento, il ramo di rilascio dovrebbe essere in uno stato rilasciabile stabile.
  7. Dopo un rilascio, Dev, QA e CR vengono lanciati dalla linea principale.

@Keith_Brings Questo è davvero un bel riassunto, grazie. Come hai già indicato, l'opzione C non è in realtà un'opzione poiché sto usando TFS, ma comunque interessante.
JoeGeeky,

Non vedo come può funzionare l'opzione A. Nella mia azienda, abbiamo versioni diverse per clienti diversi. Se stiamo ancora eseguendo lo sviluppo di funzionalità / hotfix sulla versione 1.0 e stiamo lavorando attivamente anche sulla versione 2.0 e forse anche su 3.0, non possiamo fare tutto questo su un ramo. Forse hai il lusso di goderti l'opzione A grazie al tuo modello di rilascio. Ma questo non è il modello di rilascio di tutti, e per quelli di noi bloccati con il creep di funzionalità o più versioni parallele, dobbiamo usare l'Opzione B.
void.pointer

6

Abbiamo filiali separate per ogni versione che pubblichiamo (circa 4 all'anno). È molto comodo quando è necessario estrarre una versione specifica.

Se hai bisogno di mantenere un paio di versioni precedenti, non penso che l'etichettatura lo farebbe. Con specifici rami di rilascio, è possibile applicare correzioni rapide a ciascun ramo separatamente (o ad una selezione di essi) senza preoccuparsi di nessuno degli altri rilasci.

Rende anche molto più semplice il confronto delle versioni quando si cerca quando è stato introdotto un bug o una funzionalità.

Non preoccuparti del numero di filiali o del tempo che trascorrono senza modifiche. Il tuo sistema di controllo delle versioni è quello di darti il ​​controllo 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, oltre 9000 file in un ramo di sviluppo, fino a 50 rami di sviluppo per le versioni su cui stiamo lavorando e, come già detto, un singolo ramo per versione che pubblichiamo. Perforce non respira nemmeno più forte.

In breve: rendi la tua vita come sviluppatore / maintainer / bug-fixer / cacciatore di problemi più semplice e non preoccuparti del numero di rami o del numero di file. Qualsiasi CV che si rispetti ce la farà.

Modificare:

Non subiamo alcuna confusione per quanto riguarda il numero di filiali che abbiamo. Il nostro schema di denominazione per le filiali di rilascio e la nostra politica sulle filiali di 1 numero 1 per le filiali di sviluppo (o lavoro) potrebbero avere qualcosa a che fare con questo.

I rami di rilascio sono denominati per il rilascio che detengono, ovvero: R2011SP1 per Service Pack versione 2011 1. I nostri rami di lavoro hanno nomi meno intelligenti: sub01, sub02, sub03 ecc. La "sotto" deriva dal fatto che tutti i rami di lavoro sono sotto-rami del ramo di accettazione. Il ramo di accettazione è quello in cui vengono raccolti tutti i problemi che sono pronti per essere rilasciati.

La nostra politica di succursale di lavoro 1 numero 1, combinata con il fatto che il nostro sistema di tracciamento dei problemi è stato personalizzato con un campo "ramo" ci consente di sapere sempre quale problema viene sviluppato in quale ramo. Quando un problema è integrato nel ramo di accettazione questo campo viene aggiornato. Ciò significa che sappiamo sempre quali problemi sono pronti per il rilascio (una volta completato 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 versione è stato rilasciato un problema.


1
Credo che tu possa derivare dalle etichette in TFS. Quindi dovresti andare bene per le hotfix sulle attuali versioni del prodotto purché non dimentichi l'etichetta.
Keith porta il

@KeithBring Proprio così, l'ho appena provato e puoi davvero derivare da un'etichetta.
JoeGeeky,

@MarjanVenema Non sono così preoccupato per il carico sul sistema quanto la confusione che può causare un gran numero di rami. Sono anche un po 'preoccupato che le modifiche apportate nello stack dei rami di rilascio non vengano unite in altri rami di rilascio che dovrebbero ottenerli, non importa la linea principale. Hai riscontrato questo tipo di problemi?
JoeGeeky,

@JoeGeeky: no, nessuna confusione. Vedi aggiornamento alla mia risposta.
Marjan Venema,

2

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

Ecco un piccolo caso di studio che ho avuto con il mio vecchio lavoro, usando il metodo B (lo abbiamo chiamato ramo per scopo ).

Per mettere la storia nel 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 attenute a una serie di funzionalità per un anno.

Lo sviluppo principale è stato inserito nel trunk fino a quando non abbiamo raggiunto uno stato completo di funzionalità per una determinata versione. A quel punto, creeremmo un ramo, dire projectname-gennaio2012 e faremo i nostri test di qualità e correzioni di errori proprio in quel ramo. Una volta che eravamo pronti per una versione pubblica, avremmo taggato il codice in quel ramo e rilasciato.

Tuttavia, lo sviluppo del rilascio non è terminato con quel tag. Inevitabilmente, abbiamo avuto clienti che hanno riscontrato bug o piccoli problemi con il rilascio. Quindi, in quel caso, tutto ciò che dobbiamo fare è tornare a quel ramo, patchare il codice e creare una nuova versione taggata del ramo gennaio2012 da rilasciare e unire le correzioni al trunk.

Nel nostro caso, questo approccio è stato favorevole perché alcuni utenti hanno preferito rimanere con versioni precedenti con un set limitato di funzionalità, o semplicemente perché il costo della distribuzione sulla loro infrastruttura di una versione completamente nuova piuttosto che un aggiornamento rapido ha causato alcuni problemi.

Quindi le domande che devi porti sono:

  • Con che frequenza rilascio?
  • Le mie versioni saranno compatibili al 100% con le versioni precedenti?
  • I miei clienti saranno d'accordo con l'aggiornamento completo 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 quella distribuzione, la compatibilità con le versioni precedenti e i client che si aggrappano alle vecchie versioni potrebbero essere rischi, l'opzione B ti farà sicuramente risparmiare molto dolore, renderà le cose molto più facili da supportare i tuoi clienti al costo minimo per gestire il disordine delle filiali.


Mi piace come definisci questa opzione. In questo caso, siamo i nostri clienti ( per così dire ) quindi l'implementazione rimarrà ampiamente sotto il nostro controllo. Siamo anche uno Scrum shop e prevediamo di avere cicli di rilascio abbastanza frequenti ( ad esempio ogni 2-4 settimane ). Mentre speriamo di supportare gli aggiornamenti continui, la compatibilità con le versioni precedenti sarà un problema solo per il tempo necessario per implementare gli aggiornamenti, quindi ... minuti forse. Da quel suono; nella tua esperienza; l'opzione B potrebbe non essere la scelta migliore per me. Grazie per l'informazione, molto interessante.
JoeGeeky,

Ah sì, in quel caso l'opzione B suona come un disordine con poco ritorno. Volevo solo evidenziare che entrambe le opzioni sono praticabili e hanno ciascuna i loro vantaggi. Ho dimenticato di menzionare esplicitamente: come gestite le correzioni? Sono inseriti esclusivamente in nuove versioni o in patch / vecchie versioni con patch?
Bushibytes,

1

Preferisco l'opzione A. Sviluppa sulle versioni trunk e branch quando sono stabili. Ciò limita significativamente il lavoro di integrazione delle correzioni rapide applicate alla versione di produzione.

Sono stato incaricato di aiutare una squadra che ha tentato l'opzione B di rimettersi in carreggiata.

Alcune cose da considerare.

  • Migrare gli hotfix in avanti attraverso tutti i rami di codice attivi. Questo può essere fatto unendo, rattoppando e / o riqualificando. Questi dovrebbero essere completamente gestiti per garantire che una correzione venga applicata a tutte le versioni appropriate, quindi al trunk.
  • Considerare i rami delle funzionalità per consentire lo sviluppo di funzionalità in modo isolato dal flusso di codice principale. Questi sono consigliati per modifiche sperimentali. Sentiti libero di abbandonare i rami delle funzionalità se la funzionalità non funziona.
  • Tagga e traccia i tuoi punti di unione.
  • Dirama le tue pubblicazioni quando richiesto. Trovo che ciò avvenga normalmente quando il rilascio è pronto per le build candidate al rilascio. In alcuni casi l'introduzione di modifiche incompatibili al tronco può forzare e ramificare in anticipo. Considera un ramo di funzionalità.

0

Ho lavorato per un certo numero di anni su un sistema che usa qualcosa tra i due schemi che descrivi. La chiave è che è in uso uno schema di numerazione multilivello. Il livello esterno è fondamentalmente la versione dell'API, che è gestita sui rami (con opportune fusioni incrociate quando qualcosa deve essere riparato su più rami) e il livello interno è la versione esatta effettuata, che è gestita con tag.

In particolare, se sappiamo quale versione esatta ha un cliente, sappiamo esattamente da quale fonte è stato creato il codice e possiamo fare un duplicato esatto in modo da poter vedere esattamente cosa sta succedendo. Questo è molto importante per il supporto! Tuttavia, il livello esterno dei rami, le versioni API che attualmente rilasciamo, 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, creiamo un nuovo ramo per supportarlo da (in modo che il trunk possa essere sempre orientato allo sviluppo hard-core) e consideriamo se dovremmo terminare la vita dell'attuale supporto più vecchio ramo.

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


0

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

La ramificazione / fusione è un ottimo strumento quando viene eseguita in piccoli pezzi. La difficoltà non sta nel creare un ramo (che è stupido facile), né nel spingere una settimana di lavoro sull'albero (di solito è anche facile) ... è nel far sì che il sistema CI dietro il controllo del codice sorgente funzioni automaticamente per tu.

Perché la ramificazione è controversa se il sistema non crea e non esegue automaticamente test per la tua filiale.

Avevamo personalizzato il flusso di lavoro di compilazione 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 (al contrario di una nuova sottocartella sotto una radice di sviluppo). Era fluido, facile da ramificare, facile da uccidere un ramo e abbiamo ottenuto feedback continui dal nostro sistema per compilazioni e test.

Vedo molte persone dichiarare quanto siano impossibili queste strategie sotto TFS, e credo che sia dovuto alla mancanza di familiarità con le possibilità di un motore di build basato su XAML. TFS non è solo il controllo del codice sorgente, è un'intera soluzione e dovrebbe essere utilizzata come tale.

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.