Primeiro, eu sei sobre isso: como você organizaria um repositório Subversion para projetos de software internos? A seguir, a questão real: minha equipe está reestruturando nosso repositório e estou procurando dicas sobre como organizá-lo. (SVN neste caso). Aqui está o que descobrimos. Temos um repositório, vários projetos e várias referências cruzadas svn: externals
\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
Para limpar o vocabulário: Solução significa produto único, Projeto é um Projeto do Visual Studio (que resulta em um único .dll ou .exe)
É assim que planejamos fazer o layout do repositório. O principal problema é que temos várias soluções, mas queremos compartilhar projetos entre soluções. Achamos que realmente não havia sentido em mover esses projetos compartilhados para suas próprias soluções e, em vez disso, decidimos usar svn: externals para compartilhar projetos entre soluções. Também queremos manter um conjunto comum de ferramentas e bibliotecas de terceiros em um lugar no repositório, e eles fazem referência a eles em cada Solução com svn: externals.
O que você acha desse layout? Especialmente sobre o uso de svn: externals. Não é uma solução ideal, mas considerando todos os prós e contras, é a melhor que poderíamos imaginar. Como você faria?
fonte
Respostas:
Se você seguir minhas recomendações abaixo (eu faço há anos), você será capaz de:
- coloque cada projeto em qualquer lugar no controle de origem, desde que você preserve a estrutura do diretório raiz do projeto para baixo
- construir cada projeto em qualquer lugar em qualquer máquina, com risco mínimo e preparação mínima
- construir cada projeto completamente autônomo, contanto que você tenha acesso às suas dependências binárias (diretórios "biblioteca" e "saída" locais)
- construir e trabalhar com qualquer combinação de projetos, uma vez que são independentes
- construir e trabalhar com várias cópias / versões de um único projeto, uma vez que são independentes
- evite sobrecarregar seu repositório de controle de origem com arquivos ou bibliotecas gerados
Eu recomendo (aqui está a carne):
Defina cada projeto para produzir um único produto primário, como .DLL, .EXE ou .JAR (padrão com Visual Studio).
Estruture cada projeto como uma árvore de diretórios com uma única raiz.
Crie um script de construção automatizado para cada projeto em seu diretório raiz que o construirá do zero, sem dependências em um IDE (mas não evite que seja construído no IDE, se possível).
Considere projetos nAnt para .NET no Windows ou algo semelhante com base em seu sistema operacional, plataforma de destino, etc.
Faça com que cada script de construção de projeto referencie suas dependências externas (de terceiros) de um único diretório de "biblioteca" local compartilhado, com cada binário TOTALMENTE identificado pela versão:
%DirLibraryRoot%\ComponentA-1.2.3.4.dll
,%DirLibraryRoot%\ComponentB-5.6.7.8.dll
.Faça com que cada script de construção de projeto publique a entrega primária em um único diretório de "saída" compartilhado local:
%DirOutputRoot%\ProjectA-9.10.11.12.dll
,%DirOutputRoot%\ProjectB-13.14.15.16.exe
.Faça com que cada script de construção de projeto referencie suas dependências por meio de caminhos absolutos configuráveis e com versão completa (veja acima) nos diretórios "library" e "output", E NENHUM ONDE MAIS.
NUNCA deixe um projeto referenciar diretamente outro projeto ou qualquer um de seus conteúdos - permita apenas referências aos produtos primários no diretório "output" (veja acima).
Faça com que cada script de construção de projeto referencie suas ferramentas de construção necessárias por meio de um caminho absoluto configurável e com versão completa:
%DirToolRoot%\ToolA\1.2.3.4
,%DirToolRoot%\ToolB\5.6.7.8
.Faça cada projeto script de construção de conteúdo fonte de referência por um caminho absoluto relativo ao diretório raiz do projeto:
${project.base.dir}/src
,${project.base.dir}/tst
(sintaxe varia de acordo com ferramenta de construção).SEMPRE exija um script de construção de projeto para fazer referência a CADA arquivo ou diretório por meio de um caminho absoluto e configurável (com raiz em um diretório especificado por uma variável configurável):
${project.base.dir}/some/dirs
ou${env.Variable}/other/dir
.NUNCA permita que um script de construção de projeto faça referência a QUALQUER COISA com um caminho relativo como
.\some\dirs\here
ou..\some\more\dirs
, SEMPRE use caminhos absolutos.NUNCA permita que um script de construção de projeto faça referência a QUALQUER COISA usando um caminho absoluto que não tenha um diretório raiz configurável, como
C:\some\dirs\here
ou\\server\share\more\stuff\there
.Para cada diretório raiz configurável referenciado por um script de construção de projeto, defina uma variável de ambiente que será usada para essas referências.
Tente minimizar o número de variáveis de ambiente que você deve criar para configurar cada máquina.
Em cada máquina, crie um script de shell que define as variáveis de ambiente necessárias, que é específico para ESSA máquina (e possivelmente específico para aquele usuário, se relevante).
NÃO coloque o script de shell de configuração específico da máquina no controle de origem; em vez disso, para cada projeto, envie uma cópia do script no diretório raiz do projeto como um modelo.
REQUIRE cada script de construção de projeto para verificar cada uma de suas variáveis de ambiente e aborte com uma mensagem significativa se não estiverem definidas.
REQUIRE cada script de construção de projeto para verificar cada um de seus executáveis de ferramenta de construção dependentes, arquivos de biblioteca externa e arquivos de entrega de projeto dependentes, e aborte com uma mensagem significativa se esses arquivos não existirem.
RESISTA à tentação de comprometer QUALQUER arquivo gerado no controle de origem - sem entregas do projeto, sem origem gerada, sem documentos gerados, etc.
Se você usar um IDE, gere todos os arquivos de controle de projeto que puder e não os envie para o controle de origem (isso inclui arquivos de projeto do Visual Studio).
Estabeleça um servidor com uma cópia oficial de todas as bibliotecas e ferramentas externas, para ser copiado / instalado nas estações de trabalho do desenvolvedor e nas máquinas de construção. Faça backup dele, junto com seu repositório de controle de origem.
Estabeleça um servidor de integração contínua (máquina de construção) SEM qualquer ferramenta de desenvolvimento.
Considere uma ferramenta para gerenciar suas bibliotecas externas e produtos, como Ivy (usado com Ant).
NÃO use o Maven - ele inicialmente o deixará feliz e, eventualmente, o fará chorar.
Observe que nada disso é específico do Subversion, e a maioria é genérico para projetos direcionados a qualquer sistema operacional, hardware, plataforma, linguagem, etc. Eu usei um pouco de sintaxe específica do sistema operacional e da ferramenta, mas apenas para ilustração- -Eu confio que você traduzirá para o seu sistema operacional ou ferramenta de escolha.
Observação adicional sobre as soluções do Visual Studio: não as coloque no controle de origem! Com essa abordagem, você não precisa deles ou pode gerá-los (assim como os arquivos de projeto do Visual Studio). No entanto, acho melhor deixar os arquivos da solução para desenvolvedores individuais criarem / usarem como acharem adequado (mas não registrados no controle de origem). Eu mantenho um
Rob.sln
arquivo em minha estação de trabalho do qual faço referência aos meus projetos atuais. Como meus projetos são independentes, posso adicionar / remover projetos à vontade (isso significa que não há referências de dependência baseadas em projeto).Por favor, não use recursos externos do Subversion (ou similares em outras ferramentas), eles são um antipadrão e, portanto, desnecessários.
Quando você implementa a integração contínua, ou mesmo quando deseja apenas automatizar o processo de liberação, crie um script para ela. Faça um único script de shell que: pegue os parâmetros do nome do projeto (conforme listado no repositório) e nome da tag, crie um diretório temporário dentro de um diretório raiz configurável, verifique a fonte para o nome do projeto e nome da tag fornecidos (construindo o URL apropriada no caso do Subversion) para aquele diretório temporário, executa uma compilação limpa que executa testes e empacota a entrega. Este script de shell deve funcionar em qualquer projeto e deve ser verificado no controle de origem como parte de seu projeto de "ferramentas de construção". Seu servidor de integração contínua pode usar esse script como sua base para a construção de projetos ou pode até fornecê-lo (mas você ainda pode querer o seu próprio).
@VonC: Você NÃO deseja trabalhar o tempo todo com "ant.jar" ao invés de "ant-abcdjar" depois de ser queimado quando seu script de construção quebra porque você, sem saber, o executou com uma versão incompatível do Ant. Isso é particularmente comum entre Ant 1.6.5 e 1.7.0. Generalizando, você SEMPRE deseja saber qual versão específica de CADA componente está sendo usada, incluindo sua plataforma (Java ABCD) e sua ferramenta de construção (Ant EFGH). Caso contrário, você eventualmente encontrará um bug e seu primeiro GRANDE problema será rastrear quais versões de seus vários componentes estão envolvidas. É simplesmente melhor resolver esse problema antecipadamente.
fonte
Eu acredito que o Pragmatic Version Control usando Subversion tem tudo que você precisa para organizar seu repositório.
fonte
Configuramos o nosso para corresponder quase exatamente ao que você postou. Usamos a forma geral:
Embora eu não suponha que seja tão completo quanto seu exemplo, funcionou bem para nós e nos permite manter as coisas separadas. Eu gosto da ideia de cada usuário ter uma pasta "Thrash" também - atualmente, esses tipos de projetos não terminam no controle de código-fonte, e sempre achei que deveriam.
fonte
Por que ter tudo em um repositório? Por que não apenas ter um repositório separado para cada projeto (quero dizer "Solução")?
Bem, pelo menos eu usei a abordagem de um projeto por repositório. Sua estrutura de repositório parece complicada demais para mim.
E quantos projetos você planeja colocar neste grande repositório? 2? 3? 10? 100?
E o que você faz quando cancela o desenvolvimento de um projeto? Basta excluí-lo da árvore do repositório para que seja difícil encontrá-lo no futuro. Ou deixá-lo deitado para sempre? Ou quando você deseja mover um projeto para outro servidor completamente?
E a bagunça de todos esses números de versão? Os números da versão de um projeto vão como 2, 10, 11, enquanto o outro vai como 1, 3, 4, 5, 6, 7, 8, 9, 12 ...
Talvez eu seja tolo, mas gosto de um projeto por repositório.
fonte
Eu acho que a principal desvantagem da estrutura proposta é que os projetos compartilhados serão versionados apenas com a primeira solução à qual eles foram adicionados (a menos que svn: externals seja mais sofisticado do que estou imaginando). Por exemplo, quando você cria uma ramificação para a primeira versão da Solução2, Projeto1 não será ramificada, pois reside na Solução1. Se você precisar construir a partir desse branch posteriormente (versão QFE), ele usará a versão mais recente do Projeto1 em vez da versão do Projeto1 no momento do branch.
Por esse motivo, pode ser vantajoso colocar os projetos compartilhados em uma ou mais soluções compartilhadas (e, portanto, diretórios de nível superior em sua estrutura) e, em seguida, ramificá-los a cada lançamento de qualquer solução.
fonte
Para aumentar o problema do caminho relativo:
Não tenho certeza se é um problema:
Basta verificar a Solution1 / trunk no diretório chamado "Solution1", idem para a Solution2: o objetivo dos 'diretórios' que realmente representam os ramos é não ficarem visíveis depois de importados para um espaço de trabalho. Portanto, caminhos relativos são possíveis entre 'Solução1' (na verdade, 'Solução1 / tronco') e 'Solução2' (Solução2 / tronco).
fonte
RE: o caminho relativo e o problema de arquivo compartilhado -
Parece que isso é específico do svn, mas isso não é um problema. Outra pessoa já mencionou repositórios separados e essa é provavelmente a melhor solução que posso pensar no caso em que você tem projetos diferentes referindo-se a outros projetos arbitrários. Caso você não tenha arquivos compartilhados, a solução OP (assim como muitas outras) funcionará bem.
Ainda estamos trabalhando nisso e tenho 3 esforços diferentes (clientes diferentes) que tenho que resolver agora, uma vez que assumi a configuração do controle de versão inexistente ou ruim.
fonte
Eu tenho um layout semelhante, mas meu tronco, galhos e etiquetas estão no topo. Portanto: / trunk / main, / trunk / utils, / branches / release /, etc.
Isso acabou sendo muito útil quando queríamos experimentar outros sistemas de controle de versão porque muitas das ferramentas de tradução funcionavam melhor com o layout SVN básico do livro didático.
fonte