Estrutura do Repositório Mercurial com comunicações corporativas pesadas, gerenciamento de configuração e requisitos de teste


16

Eu sou outro usuário do Subversion lutando para me reeducar no Tao do controle de versão distribuído.

Ao usar o Subversion, eu era um grande fã da abordagem de projeto menor e, com a maioria dos meus ex-empregadores, estruturamos nossas ramificações de repositório; tags e tronco da seguinte forma:

branches-+
         +-personal-+
         |          +-alice-+
         |          |       +-shinyNewFeature
         |          |       +-AUTOMATED-+
         |          |                   +-shinyNewFeature
         |          +-bob-+
         |                +-AUTOMATED-+
         |                            +-bespokeCustomerProject
         +-project-+
                   +-shinyNewFeature
                   +-fixStinkyBug
tags-+
     +-m20110401_releaseCandidate_0_1
     +-m20110505_release_0_1
     +-m20110602_milestone
trunk

Dentro da própria árvore de origem, usaríamos (algo como) a seguinte estrutura:

  (src)-+
        +-developmentAutomation-+
        |                       +-testAutomation
        |                       +-deploymentAutomation
        |                       +-docGeneration
        |                       +-staticAnalysis
        |                       +-systemTest
        |                       +-performanceMeasurement
        |                       +-configurationManagement
        |                       +-utilities
        +-libraries-+
        |           +-log-+
        |           |     +-build
        |           |     +-doc
        |           |     +-test
        |           +-statistics-+
        |           |            +-build
        |           |            +-doc
        |           |            +-test
        |           +-charting-+
        |           |          +-build
        |           |          +-doc
        |           |          +-test
        |           +-distributedComputing-+
        |           |                      +-build
        |           |                      +-doc
        |           |                      +-test
        |           +-widgets-+
        |                     +-build
        |                     +-doc
        |                     +-test
        +-productLines-+
        |              +-flagshipProduct-+
        |              |                 +-coolFeature
        |              |                 +-anotherCoolFeature
        |              |                 +-build
        |              |                 +-doc
        |              |                 +-test
        |              +-coolNewProduct
        +-project-+
                  +-bigImportantCustomer-+
                  |                      +-bespokeProjectOne
                  |                      +-bespokeProjectTwo
                  +-anotherImportantCustomer-+
                                             +-anotherBespokeProject

A idéia era (e ainda é) usar a estrutura do repositório para ajudar a estruturar a comunicação entre a equipe de engenharia; a parte do negócio voltada para o cliente e vários outros interessados ​​e especialistas em domínio.

A saber: os documentos de origem que estão em um dos diretórios "projeto" são usados ​​(e ganham dinheiro) apenas uma vez. Os documentos que estão em um dos diretórios "productLines" ganham dinheiro quantas vezes um produto dessa linha específica é vendido. Os documentos que ficam em um dos diretórios de "bibliotecas" ganham dinheiro tantas vezes quanto os produtos que os utilizam são vendidos.

Isso torna explícita a noção de amortização de custos e ajuda a criar suporte para a reutilização de documentos de origem nos negócios.

Isso também significa que existe uma estrutura comum sobre a qual nossas ferramentas de automação de construção podem operar. (Nossos scripts de construção percorrem a árvore de origem procurando por pastas "construídas", nas quais eles encontram arquivos de configuração que especificam como cada componente deve ser construído; um processo semelhante ocorre para geração e teste de documentação).

Significativamente, os produtos nos quais trabalho normalmente levam muito tempo para executar testes de medição e caracterização de desempenho; de 20 a 200 horas; gerar algo entre vários GB e vários TB de resultados de testes processados ​​/ dados intermediários (que devem ser armazenados e vinculados a uma configuração específica do sistema para que a melhoria de desempenho ao longo do tempo possa ser medida). Esse problema torna o gerenciamento de configuração uma consideração importante e também impõe alguns requisitos para centralização, pois geralmente os recursos computacionais necessários para executar os testes de medição e caracterização de desempenho são limitados; (um pequeno cluster de 64 a 128 núcleos).

Como uma nota final; o sistema de integração contínua sabe que precisa acionar uma compilação; análise estática; teste de fumaça e teste de unidade sempre que o tronco é modificado, toda vez que qualquer ramificação "tag" é modificada e cada vez que qualquer ramificação "AUTOMATIZADA" é modificada. Dessa forma, desenvolvedores individuais podem usar o sistema de IC com suas ramificações pessoais, um recurso importante, o IMHO.

Agora, aqui está a minha pergunta: como posso replicar todas as opções acima (e melhorar, se possível) com o Mercurial.

--editar:

Minha linha de pensamento atual é usar um repositório central do Subversion, para definir a estrutura geral, mas permitir o uso do hg como um cliente para que os desenvolvedores possam ter repositórios disponíveis localmente.


1
Uau. Uma boa resposta para isso será um ensaio muito longo, eu acho.
Ed James

Penso que a questão principal é como e onde estão as mesclagens de código, pois provavelmente definirão o caminho de menor resistência. Então, como o código é mesclado?
Wyatt Barnett

Normalmente, uma mesclagem pode vir de uma ramificação pessoal para uma ramificação de projeto ou recurso e depois para o tronco. Eu nunca tive muitas dificuldades com mesclagens (estávamos usando o TortoiseSVN no Win32), embora nunca tenhamos executado por muito tempo (uma iteração no máximo) sem nos integrar novamente ao tronco. De qualquer maneira, tendíamos a fazer a maior parte do nosso trabalho em tronco, embora o objetivo fosse simplificar o gerenciamento de pessoas em vez do fluxo de trabalho de desenvolvimento. (Um dev-chumbo, muitos desenvolvedores que trabalham de forma independente, por isso, ter tudo em tronco tornou mais fácil no dev-liderança para acompanhar o que estava acontecendo.)
William Payne

Um ponto importante foi a grande dependência de testes conduzidos pelo sistema de IC, principalmente no nível de teste do sistema. Isso foi para ajudar a criar confiança de que diferentes desenvolvedores não estavam interferindo entre si e promover uma mentalidade de muitas pequenas iterações. (Além disso, o trabalho pesado computacional necessário para executar os testes do sistema significava que havia menos disputas por recursos computacionais se as pessoas trabalhassem principalmente no tronco).
William Payne

Respostas:


10

A resposta de Spoike é excelente, mas acho que vale a pena acrescentar algumas coisas que são grandes demais para comentários.

Organização da filial

Com o Mercurial, você pode felizmente ignorar todo o seu primeiro organograma. Como diz o Spoke, cada repositório possui seu próprio conjunto de tags, ramificações (nomeadas e anônimas) e pode ser organizado de acordo com a necessidade do negócio.

Se bespokeProjectTwoprecisar de uma versão especial docharting biblioteca, você deverá ramificar charting, adicionar os novos recursos e usá-lo bespokeProjectTwo. As novas instalações (e seus bugs) não seriam usadas por outros projetos que fizessem referência à chartingbiblioteca padrão . Se a chartingbiblioteca principal tiver bugs corrigidos, você poderá mesclar essas alterações na ramificação. Se outros projetos também precisassem dessas instalações, você poderia obter esses projetos para usar a ramificação especial ou mesclar a ramificação na linha principal e fechá-la.

Além disso, nada impede que você tenha uma política para estruturar nomes de filiais para fornecer recursos específicos, como suas filiais de AUTOMATION.

Organização do diretório

Não há razão para que você não possa manter seu diretório de origem exatamente como no Mercurial. A única diferença é que enquanto no Subversion você tem um único monolítico(src) repositório , no Mercurial é melhor dividir em repositórios que são agrupados logicamente. Da estrutura da árvore de origem, provavelmente extrairia cada um dos seguintes como repositórios individuais:

src-+
      +-(developmentAutomation)
      +-libraries-+
      |           +-(log)
      |           +-(statistics)
      |           +-(charting)
      |           +-(distributedComputing)
      |           +-(widgets)
      +-productLines-+
      |              +-(flagshipProduct)
      |              +-(coolNewProduct)
      +-project-+
                +-bigImportantCustomer-+
                |                      +-(bespokeProjectOne)
                |                      +-(bespokeProjectTwo)
                +-anotherImportantCustomer-+
                                           +-(anotherBespokeProject)

Isso permite que qualquer produto ou projeto sob medida use qualquer combinação de bibliotecas, em qualquer revisão. Dê uma olhada nos sub-repositórios mercuriais para uma maneira fácil de gerenciar quais bibliotecas são usadas para qualquer versão de um produto ou projeto.

Fluxo de trabalho

Uma alternativa ao fluxo de trabalho sugerido por Spoike (o desenvolvedor recebe do repo abençoado, trabalha localmente, emite uma solicitação de recebimento e, finalmente, o integrador realiza essas alterações e as mescla) seria usar o sistema de integração contínua como intermediário.

Como antes, o desenvolvedor retira do repositório abençoado e trabalha localmente, mas, quando concluído, retira-o do repositório abençoado e se fundem antes de avançar para um repositório não abençoado. Quaisquer alterações no repositório não abençoado são revisadas (manual ou automaticamente) e movidas para o repositório abençoado somente se forem aprovadas.

Isso significa que o integrador aceitou ou rejeitou apenas uma alteração, não faz a mesclagem. Na minha experiência, é quase sempre melhor para o desenvolvedor que escreveu o código executar a mesclagem do que para outra pessoa.

Conforme sugerido no livro mercurial, ganchos podem ser usados ​​para automatizar este procedimento:

Quando alguém envia um conjunto de alterações para o servidor de onde todos recebem, o servidor testará o conjunto de alterações antes de aceitá-lo como permanente e o rejeitará se falhar na aprovação no conjunto de testes. Se as pessoas extraírem apenas alterações deste servidor de filtragem, isso servirá para garantir que todas as alterações extraídas pelas pessoas sejam examinadas automaticamente.

Outros problemas

O problema de grandes conjuntos de dados de teste também pode ser resolvido colocando esses dados em um sub-repositório mercurial . Isso impedirá que o repositório de código fique cheio de dados de teste, mantendo os dados de teste sob controle de revisão.


Mais uma vez, outra resposta excelente e informativa. Obrigado.
William Payne

RE: Organização da Filial. Concordo que o primeiro organograma possa ser felizmente ignorado. De qualquer maneira, não comunicou o fluxo de trabalho particularmente bem e, portanto, não estava fornecendo utilidade real além do reforço da convenção. Gostaria de substituí-lo, no entanto, por algo que comunique fortemente um fluxo de trabalho (o mais simples possível) e incentive confirmações frequentes. Talvez chamar o ramo principal de "tronco / desenvolvimento" "diariamente" faria isso?
William Payne

RE: Organização do diretório. Eu estava usando a organização do diretório de origem como um meio subliminar de comunicação; impor uma estrutura implícita na organização do código (e através dela no negócio como um todo). Estou começando a entender que o Mercurial tende a ser usado de uma maneira muito, muito flexível; mas realmente quero restringir parte dessa flexibilidade para impor uma estrutura à maneira como as pessoas pensam sobre os negócios, impondo uma estrutura à maneira como seus documentos são organizados em suas estações de trabalho e em nossas áreas de armazenamento em rede. (Mais comms corporativa do que tecnologia.)
William Payne

RE: Fluxo de trabalho. Eu acho que o fluxo de trabalho mais simples seria extrair de um repositório "diário", trabalhar localmente e depois (frequentemente) retornar ao repositório "diário", iniciando análises estáticas, testes de fumaça e testes de regressão através do sistema de CI. Fico feliz que o repo principal seja "quebrado", desde que eu saiba sobre ele, e enquanto ele for corrigido novamente rapidamente. Na verdade, estou pensando em comprometer-se com o repo "diário" da única maneira que se pode compilar e construir, para incentivar confirmações frequentes e boa cobertura de teste. (Muito mais importante do que a capacidade de trabalhar isoladamente, IMHO).
William Payne

@WilliamPayne - Obrigado. Embora o Mercurial seja flexível, com repositórios, ramificações e ganchos apropriados, você pode criar as restrições que desejar, no nível organizacional ou de repositório. Pessoalmente, eu começaria simplesmente com controles organizacionais e alguns ganchos de IC e estenderia esses controles no futuro à medida que suas necessidades se tornassem aparentes. Além disso, o uso criterioso de sub-repositórios poderia, por exemplo, incentivar as pessoas a fazer check-out localmente na mesma estrutura que está no servidor, por exemplo, tendo productLinesou bigImportantCustomercomo super-repositórios.
Mark Booth

9

Ok, tentando responder a isso simplesmente.

O que você precisa saber

Primeira coisa que você precisa saber: O Mercurial é um controle de versão distribuído e possui algumas propriedades que você deve conhecer listadas abaixo.

  • A fonte vem de um repositório, onde esse repositório pode ser clonado. Todos os repositórios clonados podem compartilhar código entre si através da sincronização (com comandos pull e push, que podem ter acesso restrito).
  • Todo usuário que possui uma cópia do código possui um clone do repositório. Se eles desejam ramificar, podem fazê-lo em seu clone local. Isso significa que você não precisa organizar como cada usuário deve ramificar. Eles podem fazer isso por si mesmos.
  • Tags são criadas no mercurial por um commit (que é o mesmo que tags rígidas no git). Isso significa que você não precisa de um diretório dentro da estrutura do seu repositório para tags.
  • O modelo usual com o qual as pessoas trabalham no DVCS (que é empregado no github e no bitbucket) é fazê-lo semi-centralizado.

    Cada usuário possui um repositório público (em algum compartilhamento ou em um servidor seguro) e um repositório privado (em suas próprias estações de trabalho). Ambos são clones do repositório "abençoado" de um integrador. Sempre que acharem que estão prontos para publicar seu código, poderão enviar as alterações para o repositório público. Um integrador pode então escolher quais usuários inserir código no repositório "abençoado".

    Se o integrador não puder mesclar o código de algum usuário facilmente, as alterações serão rejeitadas e cabe a esse usuário específico atualizar seu repositório e corrigir a mesclagem. Geralmente, não é tão difícil se você mesclar com frequência (pois é menos código que precisa ser mesclado) e geralmente esse usuário deve saber o que deu errado com a mesclagem.

Configuração de repositórios por projeto

Portanto, a configuração usual é que, para cada projeto, exista o seguinte:

  • Um repositório público somente leitura pelo qual o integrador é responsável. É "abençoado".

    Ou seja, todos os usuários podem obter / buscar conteúdo, mas não têm acesso para enviá-lo.

  • Cada usuário pode ter seu próprio clone público do repositório.

    A configuração mais fácil é colocar em uma unidade de compartilhamento (embora você possa considerar a hospedagem como o bitbucket). O integrador recebe solicitações de recebimento dos usuários e tenta extrair o novo código desses repositórios. Quando as mesclagens são feitas sem problemas, elas são colocadas no repositório somente leitura. Caso contrário, os usuários são solicitados a corrigir os conflitos de mesclagem que surgem atualizando e mesclando-os localmente.

  • Cada usuário pode ter seus próprios clones particulares do repositório.

    A boa prática é extrair do clone público, mas não importa se eles extraem do público ou do integrador. Todas as confirmações são identificáveis ​​de forma exclusiva, portanto, a fusão das confirmações que você esqueceu de buscar no público é relativamente fácil de corrigir (empurrando as alterações do privado para o público, ele obtém automaticamente as alterações do integrador).

Organização do código fonte

Como em como organizar a própria fonte do projeto, é algo que você precisa pensar. Se um artefato precisar ser controlado pela fonte, coloque-o no controle da fonte. Pessoalmente, não gosto da ideia de fazer check-in de artefatos feitos pela construção ou tempo de execução (devido ao alto risco de conflitos de mesclagem nesses tipos de artefatos), como binários ou arquivos de log.

Você também pode verificar a configuração, desde que facilite o andamento dos desenvolvedores e não atrapalhe a configuração de releases ou ambiente de produção / produção (como configurações de aplicativos / servidores da web). Isso leva à noção de que se a configuração que você dificulta seriamente os desenvolvedores a começarem dentro de cinco minutos após o check-out do código, ele precisa ser refatorado. Outro requisito é que deve ser muito difícil para os desenvolvedores atrapalharem o ambiente de lançamento ou produção / produção.

Você mencionou que possui dados de teste que precisam estar vinculados a alguma versão do código. Agora isso é um pouco mais complicado, porque sistemas DVCS como Mercurial e Git tendem a ficar lentos quando você faz check-in de dados ENORME. Na minha experiência, fica realmente insuportável após 5 GB de arquivos binários (sua milhagem pode variar, portanto, você deve testar como funciona para você). No entanto, eu recomendo que você coloque os dados gerados em seu próprio repositório e faça com que seu sistema de teste os marque adequadamente ao fazer o check-in (e / ou criar arquivos de texto para os mesmos fins de metadados).

Eu espero que isso tudo faça sentido. Comente abaixo se eu perdi alguns detalhes ou se algo precisar de mais explicações e vou tentar editar.


+1 para uma resposta muito agradável com vários pontos muito úteis. Em resposta à primeira seção da sua resposta, eu não entendi o significado de cada usuário ter seu próprio repositório público. Talvez eu precise pensar mais sobre como os fluxos de trabalho ponto a ponto poderiam ser organizados.
William Payne

Em resposta à segunda seção da sua resposta, o objetivo (em minha opinião) de ter um único repositório para toda a organização é criar uma imagem mental compartilhada de como o trabalho é estruturado e facilitar a localização de componentes que possam ser reutilizado. (Muito mais a Catedral do que o Bazar, mas esse é o ambiente em que trabalho). Eu realmente gostaria de saber como alcançar o mesmo senso de organização estruturada (sistema de arquivamento) com um DCVS.
William Payne

Em resposta à terceira seção da sua resposta: Concordo plenamente que o sistema de controle de origem é para documentos de origem e que artefatos derivados não pertencem a ele. Também concordo que não é prático armazenar binários grandes de qualquer descrição no VCS. Entretanto, acredito que você pode armazenar binários grandes em um local de rede acordado, com um nome definido, e referenciá-los de dentro do VCS. Por exemplo, os ambientes de construção podem ser armazenados como imagens de disco de VM nomeadas e referenciadas nos vários scripts de construção. (por exemplo: construa-me em build_env_A). O mesmo vale para os dados de teste.
William Payne

No passado, eu usei uma hierarquia de diretórios em uma unidade de rede, onde os nomes dos diretórios são derivados do número de revisão do subversion + hash do local da filial para vincular arquivos intermediários e resultados de testes a revisões específicas. Isso significa que temos rastreabilidade sem a necessidade de armazenar arquivos derivados no controle de versão.
William Payne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.