La risposta dipende dalle dimensioni del team, dalla qualità del controllo del codice sorgente e dalla capacità di unire correttamente serie di modifiche complesse. Ad esempio nel controllo del codice sorgente completo come CVS o SVN l'unione può essere difficile e potresti stare meglio con il primo modello, mentre se utilizzi un sistema più complesso come IBM ClearCase e con un team di dimensioni maggiori potresti essere migliore con il secondo modello o una combinazione dei due.
Personalmente separerei il modello del ramo delle caratteristiche, in cui ogni caratteristica principale è sviluppata su un ramo separato, con rami secondari delle attività per ogni modifica effettuata dal singolo sviluppatore. Man mano che le funzionalità si stabilizzano, vengono unite al trunk, che viene mantenuto ragionevolmente stabile e supera tutti i test di regressione in ogni momento. Man mano che ti avvicini alla fine del tuo ciclo di rilascio e tutti i rami delle funzionalità si fondono, stabilisci e ramifica un ramo del sistema di rilascio su cui esegui solo correzioni di bug di stabilità e backport necessari, mentre il tronco viene utilizzato per lo sviluppo della versione successiva e tu di nuovo diramazione per nuovi rami di funzionalità. E così via.
In questo modo il trunk contiene sempre il codice più recente, ma riesci a mantenerlo ragionevolmente stabile, creando etichette stabili (tag) su modifiche importanti e fusioni di funzionalità, i rami delle funzionalità sono uno sviluppo veloce con integrazione continua e i singoli rami secondari delle attività possono essere spesso aggiornato dal ramo delle funzionalità per mantenere sincronizzati tutti coloro che lavorano sulla stessa funzionalità, senza influire contemporaneamente su altri team che lavorano su funzionalità diverse.
Allo stesso tempo hai nella cronologia una serie di rami di rilascio, dove puoi fornire backport, supporto e correzioni di bug per i tuoi clienti che per qualsiasi motivo rimangono sulle versioni precedenti del tuo prodotto o anche solo sull'ultima versione rilasciata. Come per il trunk, non si imposta l'integrazione continua sui rami di rilascio, questi vengono attentamente integrati dopo aver superato tutti i test di regressione e altri controlli di qualità del rilascio.
Se per qualche motivo due funzionalità sono co-dipendenti e necessitano di modifiche reciproche, si può considerare di svilupparle entrambe sullo stesso ramo di funzionalità o di richiedere alle funzionalità di unire regolarmente parti stabili del codice al trunk e quindi aggiornare le modifiche da trunk per scambiare il codice tra i rami del trunk. Oppure, se è necessario isolare queste due funzionalità dalle altre, è possibile creare una diramazione comune da cui ramificare tali diramazioni e che è possibile utilizzare per scambiare codice tra le funzionalità.
Il modello sopra non ha molto senso con team con meno di 50 sviluppatori e un sistema di controllo del codice sorgente senza rami sparsi e capacità di fusione adeguate come CVS o SVN, il che renderebbe l'intero modello un incubo da configurare, gestire e integrare.