Mantenimento di due versioni separate del software dalla stessa base di codice nel controllo versione


45

Diciamo che sto scrivendo due diverse versioni dello stesso software / programma / app / script e le sto archiviando sotto il controllo della versione. La prima versione è una versione "Basic" gratuita, mentre la seconda è una versione "Premium" a pagamento che prende la base di codice della versione gratuita e si espande su di essa con alcune funzionalità a valore aggiunto. Eventuali nuove patch, correzioni o funzionalità devono trovare la strada in entrambe le versioni.

Attualmente sto pensando di utilizzare mastere developrami per la base di codice principale (versione gratuita) lungo master-premiume develop-premiumrami per la versione a pagamento. Quando viene apportata una modifica alla versione gratuita e unita al masterramo (dopo aver eseguito test approfonditi, developovviamente), viene copiata nel develop-premiumramo tramite il cherry-pickcomando per ulteriori test e quindi unita master-premium.

È questo il miglior flusso di lavoro per gestire questa situazione? Ci sono potenziali problemi, avvertenze o insidie ​​di cui essere consapevoli? Esiste una strategia di ramificazione migliore di quella che ho già escogitato?

Il tuo feedback è molto apprezzato!

PS Questo è per uno script PHP memorizzato in Git, ma le risposte dovrebbero applicarsi a qualsiasi lingua o VCS.

Risposte:


83

Invece di avere due versioni di codice con una base comune, è necessario progettare l'applicazione in modo tale da rendere plug-in quelle funzionalità premium guidate dalla configurazione anziché da basi di codice diverse.

Se hai paura di spedire quelle funzionalità premium (disabilitate dalla configurazione) con la versione di base puoi comunque rimuovere quel codice in un passaggio finale di build / packaging e avere solo due profili di build.

Con questo design puoi anche spedire 5 gusti diversi e diventare molto flessibile, forse anche permettendo a terzi di contribuire.


2
Sì, questo è quello a cui ho iniziato a pensare ieri sera prima di andare a letto. Grazie!
Joseph Leedy,

3
Windows moderno è progettato in questo modo, tutte le versioni hanno lo stesso codice e dispongono di funzionalità sbloccate a seconda della chiave di licenza in uso.
Mooing Duck,

39

Consiglio vivamente di non utilizzare i rami per questo scopo. In generale, dovresti considerare i rami per cose che verranno (o potrebbero essere) riunite di nuovo insieme in seguito (o per i rami di rilascio, dove alla fine fermerai lo sviluppo di uno dei rami). Nel tuo caso, non unirai mai le tue versioni "base" e "premium" e saranno entrambe mantenute indefinitamente, quindi le filiali non sono appropriate.

Invece, mantieni una versione comune del codice sorgente e usa la compilazione condizionale (es. #ifdefIn C / C ++, non certo quale sia l'equivalente per PHP) per includere o escludere le sezioni di codice che differiscono tra "base" e "premium".

Sembra che PHP potrebbe non avere una funzione di compilazione condizionale incorporata, quindi potresti usare il preprocessore C ( cpp, probabilmente lo hai già) per preelaborare il tuo codice sorgente comune e da quello, produrre un "base" e un "premio" versione senza le direttive del preprocessore. Naturalmente, se si sceglie di farlo, è necessario utilizzare makequalcosa di simile per automatizzare il processo di esecuzione del preprocessore.


Quello che stai dicendo sui rami ha un senso totale! Forse invece potrei creare un repository separato contenente solo il codice Premium e utilizzare una sorta di script di rilascio o un sottomodulo per combinarlo con il codice di base? Questo potrebbe rendere più difficile il TDD, però ...
Joseph Leedy,

14
Creare un altro repository è persino peggio che creare filiali! Sicuramente vuoi scegliere una soluzione che implichi la minima duplicazione del codice con versione.
Greg Hewgill,

2
Il punto del secondo repository è ospitare solo il codice aggiuntivo, non un'altra copia dell'intera app.
Joseph Leedy,

1
Ah, vedo, sarebbe più simile al modello di "plugin", in cui il tuo codice di base ha la capacità di caricare ed eseguire plugin (se esistono). Il codice del plug-in è separato e fornisce le funzionalità premium.
Greg Hewgill,

4
@Joseph: l'uso di due repository è appropriato solo se il controllo delle versioni delle due basi di codice è quasi indipendente l'uno dall'altro. In caso contrario, consiglio vivamente di fare ciò che Greg ha scritto e di conservare tutto in un unico repository. L'unica cosa che vorrei ripensare è l'uso del "preprocessore C". Immagino che un piccolo script scritto nella lingua che preferisci (PHP stesso va bene, Perl o Python ancora meglio) che rende una copia del tuo codice senza le caratteristiche premium (un po 'marcate) farebbe il trucco.
Doc Brown,

8

Stiamo usando 2 progetti separati, quello Basic e quello Premium che dipende dal progetto Basic. Non usare braches, di solito sono usati per le funzionalità.


Questo mi piace, perché puoi usare il tuo script di build per automatizzare la creazione di programmi di base e premium.
Neontapir,

1
in generale, sono necessari 3 progetti: parte comune, spesso organizzata come libreria e parti personalizzate per due diverse versioni.
Andriy Tylychko,

3

Mentre la maggior parte delle risposte attuali sono a favore della compilazione condizionale invece dei rami, esiste uno scenario in cui vi è un chiaro vantaggio nell'uso dei rami: se (ora o in seguito) decidi di rendere disponibile il codice sorgente della versione di base, incluso tutto il cronologia delle versioni ma escludendo tutte le funzionalità premium, è possibile farlo con l'approccio branch ma non con un singolo branch e la compilazione condizionale.

Vorrei sconsigliare la raccolta delle ciliegie, e invece unire tutte le modifiche dalla versione base alla versione premium. Non dovrebbe esserci alcuna funzionalità o correzione di bug inclusa nella versione base ma mancante nella versione premium. Per rendere il più indolore possibile, è necessario assicurarsi che il ramo premium modifichi i file comuni il meno possibile. Quindi il ramo premium dovrebbe contenere principalmente file aggiuntivi e forse alcune lievi modifiche per creare istruzioni. In questo modo, le modifiche rispetto alla versione base si uniranno automaticamente senza causare conflitti.

La risposta di Greg ha suggerito che "si considerano i rami per cose che saranno (o potrebbero essere) riunite di nuovo insieme in seguito". Con l'approccio che ho appena descritto questo è il caso, ad eccezione che il ramo finale per tutti i commit sarà master-premiumnon master(che è in realtà master-basic).

Ovviamente anche i sottomoduli sarebbero un'opzione. Dipende dal tuo processo di compilazione, ma se riesci a trasformare la versione premium in un progetto che utilizza la versione base come modulo, andrebbe bene. Tuttavia, potresti avere un momento più difficile se a un certo punto decidi di selezionare le funzionalità dal ramo premium al ramo base. Con i sottomoduli tale modifica verrebbe rappresentata come due commit distinti, mentre con le filiali questo sarebbe un singolo commit nella versione base e la successiva unione nella versione premium saprebbe che queste modifiche sono già incluse e non hanno per essere nuovamente unito.


0

In "hardware" questo viene fatto spesso, sono sistemi venduti per controllare il disordine, mi dispiace non ricordo come si chiamano.

Una volta che la lavatrice "di fascia media" viene spedita, il suo codice non cambia se non per una correzione di bug molto importante, anche quando lo stesso codice viene cambiato nella lavatrice di "fascia bassa" che viene spedita pochi mesi dopo.

I clienti non si aspettano di ottenere aggiornamenti per una lavatrice che hanno già portato, inoltre un nuovo modello non viene spedito ogni pochi mesi.

La maggior parte di noi non vive in quel mondo, quindi fai quello che dice Greg a meno che tu non stia scrivendo software per lavatrici.

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.