Come organizzi il tuo repository di controllo della versione?

Per prima cosa, ne so questo: come organizzeresti un repository di Subversion per progetti software in house? Quindi, la domanda effettiva: 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: riferimenti incrociati esterni

\commonTools /*tools used in all projects. Referenced in each project with svn:externals*/ \NUnit.v2.4.8 \NCover.v.1.5.8 \ \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 Visual Studio (che risulta in un singolo .dll o singolo .exe)

Ecco come pensiamo di disporre il repository. Il problema principale è che abbiamo più soluzioni, ma vogliamo condividere i progetti tra le soluzioni. Pensavamo che non fosse davvero necessario spostare quei progetti condivisi nelle proprie soluzioni e invece abbiamo deciso di utilizzare svn: esterni per condividere progetti tra le soluzioni. Vogliamo anche mantenere un insieme comune di strumenti e librerie di terze parti in un posto nel repository, e li fanno riferimento in ogni soluzione con svn: esterni.

Cosa ne pensi di questo layout? Soprattutto per l’uso di svn: esterni. Non è una soluzione ideale, ma considerando tutti i pro e i contro, è il massimo che si possa pensare. Come lo faresti?

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

– metti ciascun progetto ovunque nel controllo del codice sorgente, a condizione di preservare la struttura dalla directory root del progetto

– Costruire ogni progetto ovunque su qualsiasi macchina, con un rischio minimo e una preparazione minima

– Costruisci ogni progetto completamente autonomo, purché tu abbia accesso alle sue dipendenze binarie (directory locali “library” e “output”)

– Costruisci e lavora con qualsiasi combinazione di progetti, poiché sono indipendenti

– Costruisci e lavora con più copie / versioni di un singolo progetto, poiché sono indipendenti

– evitare di ingombrare il repository di controllo del codice sorgente con file o librerie generati

Consiglio (ecco il manzo):

  1. Definire ciascun progetto per produrre un singolo deliverable primario, ad esempio .DLL, .EXE o .JAR (predefinito 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 radice che lo costruirà da zero, senza NESSUN dipendenza da un IDE (ma non impedirgli di essere costruito nell’IDE, se ansible).

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

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

  6. Ogni script di costruzione del progetto pubblica il deliverable primario in una singola directory “output” condivisa locale: %DirOutputRoot%\ProjectA-9.10.11.12.dll , %DirOutputRoot%\ProjectB-13.14.15.16.exe .

  7. Fai in modo che ogni script di costruzione del progetto faccia riferimento alle sue dipendenze tramite percorsi assoluti configurabili e completamente versione (vedi sopra) nelle directory “library” e “output”, E NON DOVE ALTRO.

  8. MAI lasciare che un progetto faccia riferimento direttamente a un altro progetto oa uno qualsiasi dei suoi contenuti – solo consentire riferimenti ai deliverable principali nella directory “output” (vedi sopra).

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

  10. Realizza ogni progetto di compilazione del contenuto sorgente di riferimento dello script con un percorso assoluto relativo alla directory radice del progetto: ${project.base.dir}/src , ${project.base.dir}/tst (la syntax varia in base allo strumento di costruzione).

  11. SEMPRE richiedono uno script di costruzione 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/dirs o ${env.Variable}/other/dir .

  12. NON permettere MAI che uno script di costruzione del progetto faccia riferimento a QUALSIASI COSA con un percorso relativo come .\some\dirs\here o ..\some\more\dirs , usa SEMPRE i percorsi assoluti.

  13. Non consentire MAI a uno script di costruzione del progetto di fare riferimento a QUALSIASI COSA usando un percorso assoluto che non ha una directory root configurabile, come C:\some\dirs\here o \\server\share\more\stuff\there .

  14. Per ogni directory root configurabile a cui fa riferimento uno script di costruzione 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, creare uno script di shell che definisca le variabili d’ambiente necessarie, che è specifico per quella macchina (ed eventualmente specifico per quell’utente, se rilevante).

  17. NON mettere lo script della shell di configurazione specifico della macchina nel controllo del codice sorgente; invece, per ogni progetto, impegnare una copia dello script nella directory radice del progetto come modello.

  18. RICHIEDI ogni script di costruzione del progetto per verificare ciascuna delle sue variabili di ambiente e abortire con un messaggio significativo se non sono definiti.

  19. RICHIEDI ogni script di costruzione del progetto per controllare ciascuno dei suoi eseguibili del tool di compilazione dipendente, i file di libreria esterni e i file deliverable del progetto dipendenti, e abortire con un messaggio significativo se questi file non esistono.

  20. RESISTENTE la tentazione di impegnare QUALSIASI file generato nel controllo del codice sorgente: nessun risultato del progetto, nessuna sorgente generata, nessun documento generato, ecc.

  21. Se si utilizza un IDE, generare tutti i file di controllo del progetto che è ansible e non vincolarli al 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 build macchine. Eseguire il backup, insieme al repository di controllo del codice sorgente.

  23. Stabilire un server di integrazione continuo (macchina di compilazione) senza NESSUN strumento di sviluppo.

  24. Considera uno strumento per la gestione di librerie esterne e risultati finali, come Ivy (utilizzato con Ant).

  25. NON usare Maven – inizialmente ti renderà felice, e alla fine farai piangere.

Nota che niente di questo è specifico di Subversion, e la maggior parte è generica per progetti mirati a qualsiasi sistema operativo, hardware, piattaforma, linguaggio, ecc. Ho usato un po ‘di syntax specifica per OS e strumento, ma solo per illustrazione- -Sono certo che tu tradurrai nel tuo sistema operativo o strumento di scelta.

Nota aggiuntiva relativa alle soluzioni Visual Studio: non metterle 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 preferibile lasciare i file della soluzione ai singoli sviluppatori per creare / utilizzare come meglio credono (ma non archiviato al controllo del codice sorgente). Rob.sln un file Rob.sln sulla mia workstation da cui faccio riferimento ai miei progetti correnti. Dato che i miei progetti sono tutti autonomi, posso aggiungere / rimuovere progetti a piacimento (ovvero nessun riferimento di dipendenza basato sul progetto).

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

Quando si implementa l’integrazione continua o anche quando si desidera automatizzare il processo di rilascio, creare uno script per esso. Crea un singolo script di shell che: prende i parametri del nome del progetto (come elencato nel repository) e il nome del tag, crea una directory temporanea all’interno di una directory root configurabile, controlla l’origine per il nome del progetto e il nome del tag specificato (costruendo il URL appropriato nel caso di Subversion) in quella directory temporanea, esegue una build pulita che esegue test e confeziona il deliverable. Questo script di shell dovrebbe funzionare su qualsiasi progetto e dovrebbe essere controllato nel controllo del codice sorgente come parte del progetto “build tools”. Il tuo server di integrazione continua può utilizzare questo script come base per la creazione di progetti, oppure potrebbe anche fornirlo (ma potresti comunque volerlo).

@VonC: NON si vuole lavorare sempre con “ant.jar” piuttosto che con “ant-abcdjar” dopo che si è bruciato quando lo script di build si interrompe perché inconsapevolmente lo si è eseguito con una versione incompatibile di Ant. Questo è particolarmente comune tra Ant 1.6.5 e 1.7.0. Generalizzando, SEMPRE volete sapere quale versione specifica di OGNI componente è in uso, compresa la vostra piattaforma (Java ABCD) e il vostro 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.

Credo che Pragmatic Version Control che usa Subversion abbia tutto il necessario per organizzare il tuo repository.

Abbiamo impostato il nostro valore quasi esattamente corrispondente a quello 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 che non sia completo come il tuo esempio, ha funzionato bene per noi e ci ha permesso di mantenere le cose separate. Mi piace l’idea che ogni utente abbia una cartella “Thrash” – al momento, quei tipi di progetti non finiscono nel controllo Sorgente, e ho sempre pensato che dovevano.

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

Bene, almeno mi sono abituato all’approccio one-project-per-repository. La tua struttura di repository mi sembra complicata.

E quanti progetti hai intenzione di inserire in questo unico grande repository? 2? 3? 10? 100?

E cosa fai quando annulli lo sviluppo di un progetto? Basta cancellarlo dall’albero del repository in modo che diventi difficile da trovare in futuro. O lasciarlo in giro per sempre? O quando vuoi spostare un progetto in 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.

Penso che il principale svantaggio della struttura proposta sia che i progetti condivisi saranno solo versionati con la prima soluzione a cui sono stati aggiunti (a meno che svn: externals sia più elaborato di quanto immaginassi). Ad esempio, quando si crea un ramo per la prima versione di Solution2, Project1 non sarà diramato poiché vive in Solution1. Se è necessario creare da quel ramo in un secondo momento (versione QFE), verrà utilizzata l’ultima versione di Project1 anziché la versione di Project1 al momento del ramo.

Per questo motivo, può essere vantaggioso collocare i progetti condivisi in una o più soluzioni condivise (e quindi nelle directory di livello superiore della struttura) e quindi dirigerle con ogni versione di ogni soluzione.

Per aggiungere al problema relativo del percorso:

Non sono sicuro che sia un problema:
Basta eseguire il checkout di Solution1 / trunk nella directory denominata “Solution1”, idem per Solution2: l’objective delle “directory” che rappresentano effettivamente i rami non è visibile una volta importato in uno spazio di lavoro. Quindi sono possibili percorsi relativi tra ‘Soluzione1’ (in realtà ‘Soluzione1 / tronco’) e ‘Soluzione2’ (Soluzione2 / tronco).

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

Sembra che questo sia specifico, ma non è un problema. Un’altra persona ha già menzionato repository separati e questa è probabilmente la soluzione migliore a cui posso pensare nel caso in cui si abbiano progetti diversi che si riferiscono ad altri progetti arbitrari. Nel caso in cui non si disponga di file condivisi, la soluzione OP (oltre a molti altri) funzionerà correttamente.

Stiamo ancora lavorando e ho 3 diversi sforzi (clienti diversi) che devo risolvere in questo momento da quando ho preso il controllo della configurazione inesistente o scarso.

Ho un layout simile, ma il mio baule, i rami, i tag in cima. Quindi: / trunk / main, / trunk / utils, / branches / release /, ecc.

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