Sembra che tu abbia alcuni problemi qui:
1. Identificazione delle funzionalità per una versione specifica
Questo è un problema di gestione del progetto e un problema di coordinamento. Sarà questa caratteristica essere rilasciato prima, allo stesso tempo, come, o dopo questo altro caratteristica? Se le versioni vogliono accadere una funzionalità alla volta, identificala. Se le funzionalità verranno raggruppate in rilasci, quindi capire quali sono i raggruppamenti e applicarli agli sviluppatori e ai decisori. Utilizzare il sistema di tracciamento o emissione dei problemi per contrassegnare le versioni. Metti in chiaro che se una caratteristica di una versione specifica è un no-go, allora tutte lo sono.
2. Strategie di ramificazione
Git-flow è la risposta semplice a problemi come questi, e spesso le persone usano una variante di git-flow anche se non sanno di cosa si tratta. Non ho intenzione di dire che è un problema per tutti i problemi, ma aiuta molto.
Sembra che tu stia riscontrando un problema con le strategie di rilascio non deterministiche, in cui le funzionalità sono approvate scattershot e qualcosa che ha iniziato lo sviluppo molto tempo fa potrebbe essere rilasciato dopo qualcosa che è iniziato più di recente: le funzionalità di salto con la rana.
I rami di lunga durata o quelli a rilascio simultaneo sono probabilmente la risposta migliore per questo tipo di problemi. Unisci (o rebase, se ti senti a tuo agio con esso) le ultime novità dal master nei tuoi rami di vecchia data. Fai attenzione a unire solo le funzionalità che sono già attive, altrimenti ti imbatterai nei problemi che hai riscontrato ora (troppe funzioni confuse su un ramo).
I rami "Hotfix" o "bugfix" sono una parte essenziale di questo processo; usali per piccole correzioni singole che hanno un breve ciclo di QA.
Dalla tua descrizione, potrebbe anche essere meglio non mantenere un ramo di "sviluppo" ufficiale. Piuttosto, diramare tutte le funzionalità dal master e creare rami di rilascio uniti una volta identificato un rilascio.
3. Ambienti
Non abbinare i rami git ai tuoi ambienti, ad eccezione di production == master. Il ramo "sviluppo" dovrebbe essere considerato spezzato. Le filiali di rilascio vengono inviate agli ambienti di test, che si tratti di un ambiente di controllo qualità o di un ambiente di gestione temporanea. Se necessario, spingere un ramo di funzionalità specifico in un ambiente.
Se hai più di un ramo delle funzioni che devono essere rilasciati separatamente ma sono in fase di test allo stesso tempo ..... ¯ \ _ (ツ) _ / ¯ .... far girare un altro server? Magari uniscili in un ramo da buttare via ... commetti correzioni / modifiche ai rami originali e ricollegali nel ramo da buttare via; fare l'approvazione finale e UAT sui singoli rami di rilascio.
4. Rimozione di funzioni non approvate da una filiale
Questo è ciò che i pensieri di cui sopra stanno cercando di evitare, perché questa è senza dubbio la cosa più dolorosa da provare. Se sei fortunato, le funzionalità sono state unite nel tuo sviluppo o testano i rami atomicamente usando i commit di unione. Se sei sfortunato, gli sviluppatori si sono impegnati direttamente nel ramo sviluppo / test.
In entrambi i casi, se ti stai preparando per una versione e hai modifiche non approvate, dovrai utilizzare Git per eseguire il backout di quelle commit non approvate dal ramo di rilascio; l'idea migliore è farlo prima di testare il rilascio.
Buona fortuna.