Come organizzi il tuo repository di controllo della versione?


108

Per prima cosa, so questo: come organizzereste un repository Subversion per progetti software interni? Successivamente, la vera domanda: il mio team sta ristrutturando il nostro repository e sto cercando suggerimenti su come organizzarlo. (SVN in questo caso). Ecco cosa ci è venuto in mente. Abbiamo un repository, più progetti e più svn: externals riferimenti incrociati

\commonTools /*tools used in all projects. Referenced in each project with svn:externals*/
   \NUnit.v2.4.8
   \NCover.v.1.5.8
   \<other similar tools>
\commonFiles /*settings strong name keys etc.*/
   \ReSharper.settings
   \VisualStudio.settings
\trash /*each member of the team has trash for samples, experiments etc*/
   \user1
   \user2
\projects
   \Solution1 /*Single actual project (Visual Studio Solution)*/
      \trunk
         \src
             \Project1 /*Each sub-project resulting in single .dll or .exe*/
             \Project2
         \lib
         \tools
         \tests
         \Solution1.sln
      \tags
      \branches
   \Solution2
      \trunk
         \src
             \Project3 /*Each sub-project resulting in single .dll or .exe*/
             \Project1 /*Project1 from Solution1 references with svn:externals*/
         \lib
         \tools
         \tests
         \Solution2.sln
      \tags
      \branches

Per cancellare il vocabolario: Soluzione significa singolo prodotto, Project è un progetto di Visual Studio (che risulta in un singolo .dll o singolo .exe)

È così che pianifichiamo di disporre il repository. Il problema principale è che abbiamo più soluzioni, ma vogliamo condividere i progetti tra le soluzioni. Abbiamo pensato che non avesse davvero senso spostare quei progetti condivisi nelle loro soluzioni, e invece abbiamo deciso di utilizzare svn: externals per condividere i progetti tra le soluzioni. Vogliamo inoltre mantenere il set comune di strumenti e le librerie di terze parti in un unico punto nel repository e farvi riferimento in ciascuna soluzione con svn: externals.

Cosa ne pensate di questo layout? Soprattutto sull'uso di svn: externals. Non è una soluzione ideale, ma considerando tutti i pro e i contro, è la migliore a cui si possa pensare. Come lo faresti?


Sei sicuro di voler dire "thrash"? O meglio "spazzatura"?
SS

Risposte:


92

Se segui i miei consigli di seguito (li ho da anni), sarai in grado di:

- metti ogni progetto ovunque nel controllo del codice sorgente, purché conservi la struttura dalla directory principale del progetto in giù

- costruire ogni progetto ovunque su qualsiasi macchina, con il minimo rischio e la minima preparazione

- Costruisci ogni progetto completamente autonomo, purché tu abbia accesso alle sue dipendenze binarie (directory "libreria" e "output" locale)

- costruire e lavorare con qualsiasi combinazione di progetti, poiché sono indipendenti

- costruire e lavorare con più copie / versioni di un singolo progetto, poiché sono indipendenti

- evita di ingombrare il tuo repository di controllo del codice sorgente con file o librerie generati

Consiglio (ecco il manzo):

  1. Definisci ogni progetto per produrre un unico deliverable principale, ad esempio .DLL, .EXE o .JAR (impostazione predefinita con Visual Studio).

  2. Struttura ogni progetto come un albero di directory con una singola radice.

  3. Crea uno script di compilazione automatizzato per ogni progetto nella sua directory principale che lo costruirà da zero, senza dipendenze da un IDE (ma non impedire che venga compilato nell'IDE, se possibile).

  4. Considera nAnt per progetti .NET su Windows o qualcosa di simile in base al tuo sistema operativo, piattaforma di destinazione, ecc.

  5. Fai in modo che ogni script di compilazione del progetto faccia riferimento alle sue dipendenze esterne (di terze parti) da una singola directory di "libreria" condivisa locale, con ogni binario di questo tipo COMPLETAMENTE identificato dalla versione: %DirLibraryRoot%\ComponentA-1.2.3.4.dll, %DirLibraryRoot%\ComponentB-5.6.7.8.dll.

  6. Fai in modo che ogni script di compilazione del progetto pubblichi il deliverable principale in una singola directory di "output" condivisa locale: %DirOutputRoot%\ProjectA-9.10.11.12.dll, %DirOutputRoot%\ProjectB-13.14.15.16.exe.

  7. Fare in modo che ogni script di compilazione del progetto faccia riferimento alle sue dipendenze tramite percorsi assoluti configurabili e con versione completa (vedere sopra) nelle directory "libreria" e "output", E NESSUN ALTRO.

  8. NON lasciate MAI che un progetto faccia direttamente riferimento a un altro progetto o ai suoi contenuti - consentite solo i riferimenti ai deliverable primari nella directory "output" (vedere sopra).

  9. Fai in modo che ogni script di compilazione del progetto faccia riferimento ai suoi strumenti di compilazione richiesti tramite un percorso assoluto configurabile e con versione completa: %DirToolRoot%\ToolA\1.2.3.4, %DirToolRoot%\ToolB\5.6.7.8.

  10. Fare ogni progetto script di build contenuti fonte di riferimento da parte di un percorso assoluto relativo alla directory radice del progetto: ${project.base.dir}/src, ${project.base.dir}/tst(sintassi varia da strumento di compilazione).

  11. SEMPRE richiede uno script di compilazione del progetto per fare riferimento a OGNI file o directory tramite un percorso assoluto e configurabile (radicato in una directory specificata da una variabile configurabile): ${project.base.dir}/some/dirso ${env.Variable}/other/dir.

  12. NON consentire MAI a uno script di compilazione del progetto di fare riferimento a NULLA con un percorso relativo come .\some\dirs\hereo ..\some\more\dirs, utilizzare SEMPRE percorsi assoluti.

  13. NON consentire MAI a uno script di compilazione del progetto di fare riferimento a NULLA utilizzando un percorso assoluto che non dispone di una directory radice configurabile, come C:\some\dirs\hereo \\server\share\more\stuff\there.

  14. Per ogni directory root configurabile a cui fa riferimento uno script di compilazione del progetto, definire una variabile di ambiente che verrà utilizzata per tali riferimenti.

  15. Tentare di ridurre al minimo il numero di variabili di ambiente che è necessario creare per configurare ogni macchina.

  16. Su ogni macchina, crea uno script di shell che definisce le variabili d'ambiente necessarie, che è specifico per QUELLA macchina (e possibilmente specifico per quell'utente, se rilevante).

  17. NON inserire lo script della shell di configurazione specifico della macchina nel controllo del codice sorgente; invece, per ogni progetto, eseguire il commit di una copia dello script nella directory principale del progetto come modello.

  18. RICHIEDERE che ogni script di compilazione del progetto controlli ciascuna delle sue variabili di ambiente e interrompa con un messaggio significativo se non sono definite.

  19. RICHIEDERE che ogni script di compilazione del progetto controlli ciascuno degli eseguibili dello strumento di compilazione dipendente, i file di libreria esterna e i file consegnabili del progetto dipendenti e interrompa con un messaggio significativo se tali file non esistono.

  20. RESISTERE alla tentazione di inserire QUALSIASI file generato nel controllo del codice sorgente: nessun risultato del progetto, nessuna fonte generata, nessun documento generato, ecc.

  21. Se usi un IDE, genera tutti i file di controllo del progetto possibili e non eseguirne il commit nel controllo del codice sorgente (inclusi i file di progetto di Visual Studio).

  22. Stabilire un server con una copia ufficiale di tutte le librerie e gli strumenti esterni, da copiare / installare sulle workstation degli sviluppatori e costruire macchine. Esegui il backup, insieme al tuo repository di controllo del codice sorgente.

  23. Stabilire un server di integrazione continua (build machine) senza strumenti di sviluppo di sorta.

  24. Considera uno strumento per la gestione delle tue librerie esterne e dei tuoi risultati, come Ivy (usato con Ant).

  25. NON usare Maven: inizialmente ti renderà felice e alla fine ti farà piangere.

Nota che niente di tutto questo è specifico di Subversion e la maggior parte è generico per progetti mirati a qualsiasi sistema operativo, hardware, piattaforma, linguaggio, ecc. Ho usato un po 'di sintassi specifica del sistema operativo e dello strumento, ma solo a scopo illustrativo- -Spero che tradurrai nel tuo sistema operativo o strumento preferito.

Nota aggiuntiva sulle soluzioni Visual Studio: non inserirle nel controllo del codice sorgente! Con questo approccio, non ne hai affatto bisogno o puoi generarli (proprio come i file di progetto di Visual Studio). Tuttavia, trovo che sia meglio lasciare i file della soluzione ai singoli sviluppatori per crearli / utilizzarli come meglio credono (ma non controllati nel controllo del codice sorgente). Conservo un Rob.slnfile sulla mia stazione di lavoro da cui faccio riferimento ai miei progetti attuali. Poiché i miei progetti sono tutti autonomi, posso aggiungere / rimuovere progetti a piacimento (ciò significa nessun riferimento alle dipendenze basato sul progetto).

Si prega di non utilizzare gli esterni di Subversion (o simili in altri strumenti), sono un anti-pattern e, quindi, non necessari.

Quando si implementa l'integrazione continua, o anche quando si desidera solo automatizzare il processo di rilascio, creare uno script per esso. Crea un singolo script di shell che: prenda i parametri del nome del progetto (come elencato nel repository) e il nome del tag, crei una directory temporanea all'interno di una directory root configurabile, controlli l'origine per il nome del progetto e il nome del tag (costruendo il URL appropriato nel caso di Subversion) a quella directory temporanea, esegue una build pulita che esegue test e impacchetta il deliverable. Questo script di shell dovrebbe funzionare su qualsiasi progetto e dovrebbe essere inserito nel controllo del codice sorgente come parte del progetto "strumenti di compilazione". Il tuo server di integrazione continua può utilizzare questo script come base per la creazione di progetti o potrebbe persino fornirlo (ma potresti comunque volerne uno tuo).

@VonC: NON vuoi lavorare sempre con "ant.jar" invece che con "ant-abcdjar" dopo esserti bruciato quando il tuo script di build si interrompe perché lo hai eseguito inconsapevolmente con una versione incompatibile di Ant. Questo è particolarmente comune tra Ant 1.6.5 e 1.7.0. Generalizzando, vuoi SEMPRE sapere quale versione specifica di OGNI componente viene utilizzata, inclusa la tua piattaforma (Java ABCD) e il tuo strumento di compilazione (Ant EFGH). Altrimenti, alla fine incontrerai un bug e il tuo primo GRANDE problema sarà rintracciare quali versioni dei tuoi vari componenti sono coinvolte. È semplicemente meglio risolvere il problema in anticipo.


6
Tanti punti da criticare ... basti dire che questa non è una ricetta universale! I punti 5 e 6 in particolare sono davvero sbagliati quando il progetto è grande e il numero di terze parti è importante: vuoi lavorare sempre con "ant.jar", non "ant1.5.4.jar" o con il prodotto myProduct .exe, non 1.3.exe
VonC

5
Tuttavia, +1 per molti altri punti che stai facendo che sono validi e parla molto bene della tua vasta esperienza sull'argomento.
VonC

3
Mi piacerebbe ascoltare e interagire con le tue critiche: ogni punto si basa sulla risoluzione di brutte esperienze con grandi progetti. Ad esempio, affrontando il problema di quali versioni sono rappresentate da Xxx.jar e Yyy.exe, soprattutto quando ci sono letteralmente una dozzina di copie a cui si fa riferimento.
Rob Williams,

2
@Rob - Puoi approfondire il tema del tuo "antipattern degli esterni"? L'ho sollevata come domanda qui: stackoverflow.com/questions/338824/…
Ken

3
@ Makis: avresti ragione, SE il # 12 non fosse bilanciato dal # 13. Ogni riferimento a un file o una directory all'interno di ogni progetto dovrebbe essere fatto tramite un percorso assoluto che inizia con una variabile di directory radice configurabile, ad esempio $ {basedir} /sub/dir/file.txt in Ant.
Rob Williams,


3

Abbiamo impostato il nostro in modo che corrisponda quasi esattamente a ciò che hai pubblicato. Usiamo la forma generale:

\Project1
   \Development (for active dev - what you've called "Trunk", containing everything about a project)
   \Branches (For older, still-evolving supported branches of the code)
       \Version1
       \Version1.1
       \Version2
   \Documentation (For any accompanying documents that aren't version-specific

Anche se suppongo non sia completo come il tuo esempio, ha funzionato bene per noi e ci consente di tenere le cose separate. Mi piace l'idea che ogni utente abbia anche una cartella "Thrash" - attualmente, quei tipi di progetti non finiscono nel controllo del codice sorgente, e ho sempre pensato che dovrebbero.


3
Sono sorpreso che tu abbia una directory separata per i documenti che non cambiano tra le versioni ... Non ho mai avuto il piacere di lavorare su un prodotto del genere! :)
ARKBAN

1

Perché avere tutto in un unico repository? Perché non avere solo un repository separato per ogni progetto (intendo "Soluzione")?

Bene, almeno sono abituato all'approccio un progetto per repository. La tua struttura del repository mi sembra complicata.

E quanti progetti pensi di mettere in questo grande archivio? 2? 3? 10? 100?

E cosa fai quando annulli lo sviluppo di un progetto? Basta eliminarlo dall'albero del repository in modo che diventi difficile da trovare in futuro. O lasciarlo in giro per sempre? O quando vuoi spostare del tutto un progetto su un altro server?

E che dire del pasticcio di tutti quei numeri di versione? I numeri di versione di un progetto vanno come 2, 10, 11, mentre l'altro va come 1, 3, 4, 5, 6, 7, 8, 9, 12 ...

Forse sono sciocco, ma mi piace un progetto per repository.


1. Un repository è una politica aziendale, non può cambiarla. 2. Avremo una dozzina di soluzioni. 3. per numero di versione intendi revisioni? Questo non è un problema per noi.
Krzysztof Kozmic

Una buona struttura del progetto dovrebbe essere ignara del resto della struttura del repository, in particolare per quanto riguarda uno o più repository. Si prega di vedere la mia risposta dettagliata.
Rob Williams,

1
Si noti che avere più repository in molti (quasi tutti?) Strumenti di controllo del codice sorgente può essere MOLTO costoso, ad esempio quando si implementa la sicurezza.
Rob Williams,

0

Penso che il principale svantaggio della struttura proposta sia che i progetti condivisi saranno aggiornati solo con la prima soluzione a cui sono stati aggiunti (a meno che svn: externals non sia più elaborato di quanto immagino). Ad esempio, quando crei un ramo per la prima versione di Solution2, Project1 non verrà ramificato poiché risiede in Solution1. Se è necessario compilare da quel ramo in un secondo momento (rilascio QFE), utilizzerà l'ultima versione di Project1 anziché la versione di Project1 al momento del ramo.

Per questo motivo, può essere vantaggioso mettere i progetti condivisi in una o più soluzioni condivise (e quindi directory di primo livello nella struttura) e poi ramificarli con ogni rilascio di qualsiasi soluzione.


Hai ragione in una certa misura. Ma possiamo aggiornare il riferimento se lo vogliamo. E anche inserire progetti condivisi nella propria soluzione non ha molto senso. Anche se mi piacerebbe trovare una soluzione migliore di svn: esterni dappertutto.
Krzysztof Kozmic

Cosa intendi per "aggiornare il riferimento se lo vogliamo"? Non vedo come saresti in grado di ramificare Project1 (che sembra desiderabile ogni volta che ramifichi Solution2) senza ramificare Solution1.
C.Dragon 76,

Si prega di vedere la mia risposta dettagliata, in particolare per NON mettere le soluzioni di Visual Studio nel controllo del codice sorgente.
Rob Williams,

0

Per aggiungere al problema relativo al percorso:

Non sono sicuro che sia un problema:
basta effettuare il checkout di Solution1 / trunk nella directory denominata "Solution1", idem per Solution2: l'obiettivo delle "directory" che rappresentano effettivamente i rami è di non essere visibili una volta importate in uno spazio di lavoro. Quindi sono possibili percorsi relativi tra "Solution1" (in realtà "Solution1 / trunk") e "Solution2" (Solution2 / trunk).


Questo si romperebbe molto facilmente, vedere la mia risposta dettagliata.
Rob Williams,

0

RE: il percorso relativo e il problema del file condiviso -

Sembra che questo sia specifico per svn, ma non è un problema. Un'altra persona ha già menzionato repository separati e questa è probabilmente la soluzione migliore a cui riesco a pensare nel caso in cui si abbiano progetti diversi che si riferiscono ad altri progetti arbitrari. Nel caso in cui non si abbiano file condivisi, la soluzione OP (così come molte altre) funzionerà bene.

Stiamo ancora risolvendo questo problema e ho 3 diversi sforzi (client diversi) che devo risolvere in questo momento da quando ho assunto la configurazione di un controllo della versione inesistente o scadente.


Avere progetti che fanno riferimento ad altri progetti crea un incubo di manutenzione perché le dipendenze crescono in modo esponenziale ei riferimenti sono MOLTO fragili. Si prega di vedere la mia risposta dettagliata.
Rob Williams,

0

Ho un layout simile, ma il mio tronco, rami, tag fino in fondo. Quindi: / trunk / main, / trunk / utils, / branch / release /, ecc.

Questo si è rivelato davvero utile quando volevamo provare altri sistemi di controllo della versione perché molti degli strumenti di traduzione funzionavano meglio con il layout SVN del libro di testo di base.

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.