Escolhendo entre projetos únicos ou múltiplos em um repositório git?

223

Em um gitambiente em que modularizamos a maioria dos projetos, enfrentamos o problema de um projeto por repositório ou vários projetos por design de repositório . Vamos considerar um projeto modularizado:

myProject/
   +-- gui
   +-- core
   +-- api
   +-- implA
   +-- implB

Hoje estamos tendo um projeto por repositório . Dá liberdade para

  • release componentes individuais
  • tag componentes individuais

Mas também é complicado para os branchcomponentes, pois muitas vezes a ramificação apirequer ramificações equivalentes coree talvez outros componentes.

Dado que desejamos releasecomponentes individuais, ainda podemos obter flexibilidade semelhante utilizando vários projetos por design de repositório .

Que experiências existem e como / por que você abordou essas questões?

Johan Sjöberg
fonte
11
Eu tenho um problema muito parecido agora. Eu preciso liberar versões diferentes de um projeto para que eles precisem estar em repositórios diferentes. Este é um pesadelo para gerenciar. Seria ótimo se houvesse uma maneira de ramificar apenas subdiretórios.
Andrew T Finnell
11
Cada módulo precisa ter números de versão separados. E nós usamos git-describe.
linquize
Estou surpreso ao ver que Bit ( bitsrc.io ) e Lerna ( github.com/lerna/lerna ) não são mencionados! Você pode saber mais aqui: hackernoon.com/...
Yoni

Respostas:

199

Existem três grandes desvantagens one project per repository, da maneira que você descreveu acima. Isso é menos verdadeiro se forem projetos verdadeiramente distintos, mas, a partir dos sons, as alterações em uma exigem mudanças em outra, o que pode realmente exagerar esses problemas:

  1. É mais difícil descobrir quando erros foram introduzidos. Ferramentas como git bisectse tornam muito mais difíceis de usar quando você divide seu repositório em subdiretórios. É possível, não é tão fácil, o que significa que a caça a insetos em tempos de crise é muito mais difícil.
  2. Rastrear todo o histórico de um recurso é muito mais difícil. Histórico atravessando comandos como git logsimplesmente não gera histórico de maneira tão significativa com estruturas de repositório fraturadas. Você pode obter alguma saída útil com submódulos ou subárvores, ou através de outros métodos de script, mas não é o mesmo que digitar tig --grep=<caseID>ou git log --grep=<caseID>digitalizar todos os commits de que você gosta. Seu histórico fica mais difícil de entender, o que o torna menos útil quando você realmente precisa.
  3. Novos desenvolvedores passam mais tempo aprendendo a estrutura do Controle de Versão antes de começarem a codificar. Todo novo trabalho requer procedimentos de seleção, mas fraturar um repositório de projetos significa que eles precisam escolher a estrutura do VC, além da arquitetura do código. Na minha experiência, isso é particularmente difícil para desenvolvedores iniciantes que vêm de lojas mais tradicionais e centralizadas que usam um único repositório.

No final, é um cálculo de custo de oportunidade. Em um ex-empregador, tivemos nosso aplicativo principal dividido em 35 sub-repositórios diferentes. Além disso, usamos um conjunto complicado de scripts para pesquisar o histórico, garantir que o estado (isto é, produção versus ramos de desenvolvimento) fosse o mesmo entre eles e implantá-los individualmente ou em massa.

Foi simplesmente demais; demais para nós, pelo menos. A sobrecarga de gerenciamento tornava nossos recursos menos ágeis, tornava as implantações muito mais difíceis, fazia com que o ensino de novos desenvolvedores demorasse muito tempo e, no final, mal conseguíamos lembrar por que fraturamos o repositório em primeiro lugar. Em um lindo dia de primavera, gastei US $ 10 por uma tarde de tempo de computação em cluster no EC2. Entreguei os acordos de recompra com algumas dúzias de git filter-branchligações. Nós nunca olhamos para trás.

Christopher
fonte
7
Como um tópico fora de questão, existem poucas coisas mais agradáveis ​​como gerente de repositório do que ganhar tempo em um sistema que pode fazer em duas horas o que seu laptop não pode fazer em 20, por menos do que o preço do almoço. Às vezes eu realmente amo a internet.
Christopher
2
Como você lançaria esses projetos individuais como lançamentos separados? Ou você nunca precisa fazer isso? Esse é o problema que tenho. Com se você precisa criar um V1 do Projeto A, e V2 do Projeto B.
Andrew T Finnell
5
Para mover-se entre o "um projeto por repo" e "múltiplos repos" considerar git-sub (boa explicação no stackoverflow.com/a/17864475/15585 )
deterb
11
Eu escrevi um script para automatizar isso para casos de uso comum: github.com/Oakleon/git-join-repos
chrishiestand
O que é uma "estrutura de VC?"
Robert Harvey
60

Christopher fez um excelente trabalho ao enumerar as desvantagens de um modelo de um projeto por repositório. Gostaria de discutir alguns dos motivos pelos quais você pode considerar uma abordagem de múltiplos repositórios. Em muitos ambientes em que trabalhei, uma abordagem com vários repositórios tem sido uma solução razoável, mas a decisão de quantos repositórios ter e onde fazer os cortes nem sempre foi fácil.

Na minha posição atual, migrei um gigantesco repositório CVS de repositório único, com mais de dez anos de história, para vários repositórios git. Desde essa decisão inicial, o número de repositórios aumentou (por meio de ações de outras equipes), a ponto de suspeitar que temos mais do que seria ideal. Alguns contratados sugeriram a fusão dos repositórios, mas eu argumentei contra isso. O projeto Wayland tem uma experiência semelhante. Em uma palestra que vi recentemente, eles tinham, a certa altura, mais de 200 repositórios git, pelos quais o líder se desculpou. Olhando para o site deles , vejo agora que eles têm 5 anos, o que parece razoável. É importante observar que unir e dividir repositórios é uma tarefa gerenciável, e não há problema em experimentar (dentro do razoável).

Então, quando você pode querer vários repositórios?

  1. Um único repositório seria muito grande para ser eficiente.
  2. Seus repositórios são fracamente acoplados ou desacoplados.
  3. Um desenvolvedor normalmente precisa apenas de um ou de um pequeno subconjunto de seus repositórios para desenvolver.
  4. Você normalmente deseja desenvolver os repositórios de forma independente e precisa sincronizá-los apenas ocasionalmente.
  5. Você deseja incentivar mais modularidade.
  6. Equipes diferentes trabalham em diferentes repositórios.

Os pontos 2 e 3 são significativos apenas se o ponto 1 for válido. Ao dividir nossos repositórios, reduzi significativamente os atrasos sofridos por nossos colegas externos, reduzi o consumo de disco e aprimorei o tráfego de rede.

4 e 5 são mais sutis. Quando você divide os repositórios, digamos, de um cliente e servidor, isso torna mais caro coordenar as alterações entre o código do cliente e do servidor. Isso pode ser positivo, pois incentiva uma interface dissociada entre os dois.

Mesmo com as desvantagens de projetos com vários repositórios, muito trabalho respeitável é feito dessa maneira - wayland e boost vêm à mente. Não acredito que um consenso sobre as melhores práticas tenha evoluído ainda e que seja necessário algum julgamento. Ferramentas para trabalhar com vários repositórios (git-subtree, git-submodule e outros) ainda estão sendo desenvolvidas e experimentadas. Meu conselho é experimentar e ser pragmático.

Spacemoose
fonte
7
Essa resposta seria ainda mais útil com uma referência para apoiar a reivindicação: "juntar e dividir repositórios é uma tarefa gerenciável".
Curinga
3
Vários repositórios também podem funcionar contra a modularidade, pois dificultam a alteração do código compartilhado. As dependências entre repositórios dificultam a integração, podem quebrar o código com mais facilidade (mesmo se você tiver boas ferramentas para verificar isso) e a ameaça de quebrar o código fora do repositório desencoraja as interfaces de refatoração, que é uma das ferramentas mais poderosas para facilitar as coisas. mais modular.
Curt J. Sampson
Tudo sobre o MicroServices e o design DDD é válido aqui. Você deve minimizar o código compartilhado.
Arwin
49

Como usamos o GitHub, na verdade, temos vários projetos em um repositório, mas garantimos que esses projetos / módulos sejam modularizados adequadamente (usamos as convenções -api e -core + Maven + verificação estática e de tempo de execução e pode até ir ao OSGi um dia para inicializar) .

O que economiza? Bem, não precisamos emitir várias solicitações pull se estivermos alterando algo pequeno em vários projetos. Problemas e Wiki são mantidos centralizados, etc.

Ainda tratamos cada módulo / projeto como um projeto independente adequado e os construímos e integramos separadamente em nosso servidor de IC etc.

Martijn Verburg
fonte
11
Muito interessante. Eu suspeitaria que este é um modelo comum no github. Se você enfrentar lançamentos de componentes individuais, emprega algo como submodulesou libera / marca todo o repositório?
Johan Sjöberg
submódulos se for necessário, mas por enquanto fazemos a versão do pai para baixo.
Martijn Verburg
No meu atual empregador, usamos uma estratégia semelhante e empacotamos metadados sobre a confirmação mais recente em um projeto nos vários arquivos manifestos de artefatos (ou seja, os resultados de git log -1 -- <project_dir>). É realmente ótimo. Esta resposta merece mais votos.
Christopher
22

Para mim, a principal diferença no uso de um ou mais de um repositório são as respostas para as seguintes perguntas:

  • As várias partes desenvolvidas pela mesma equipe, têm o mesmo ciclo de liberação, o mesmo cliente? Existem menos razões para dividir o repositório único.
  • As várias partes são altamente dependentes uma da outra? Portanto, dividir modelo, controlador e interface do usuário (mesmo quando são partes diferentes) não é muito sensato, devido à alta dependência um do outro. Porém, se duas partes tiverem apenas uma pequena dependência, que é implementada por uma interface estável que só é alterada a cada poucos anos, seria aconselhável dividir as 2 partes em 2 repositórios.

Apenas como exemplo, eu tenho um pequeno aplicativo (somente cliente), que verifica a "qualidade" de um repositório do Subversion. Existe a implementação principal, que pode ser iniciada a partir da linha de comando, e funciona bem com o Java 6. Mas comecei a implementar uma interface do usuário, que usa o JavaFX como parte do Java 8. Portanto, dividi o 2 e criei um segundo repositório (com um segundo processo de compilação), com cronograma diferente, ...

Gosto das respostas acima (votei-as), mas acho que não são a história verdadeira. Então, eu queria adicionar os argumentos para dividir os repositórios também. Portanto, a resposta real (quando dividir) pode estar em algum lugar no meio ...

mliebelt
fonte
0

Do seu exemplo, os repositórios devem ser configurados em termos de quão interdependentes eles são. Todo o raciocínio sobre o design de MicroServices e Design Orientado a Domínio se aplica aqui: em alguns casos, o código duplicado é aceitável, trabalha com interfaces, não quebra a compatibilidade a menos que você precise, etc.

Agora, na minha opinião, uma interface do usuário deve ser independente do back-end. Portanto, um repositório de projeto de interface do usuário normalmente deve conter o código da interface do usuário e o controlador de cliente. O Client Controller se conectará aos Service Controllers de maneira abstrata. Eles usarão uma abstração de cliente / API de serviço com versão separada do serviço, para que um serviço possa ser atualizado sem interromper o (s) cliente (s) (pode haver vários clientes diferentes).

Portanto, um serviço em si deve ser seu próprio repositório. Na minha opinião, o serviço é apenas um invólucro de alguma lógica comercial de ponto único. Portanto, a lógica de negócios normalmente deve ser separada da tecnologia de serviço que a hospeda. Por outro lado, a implementação do repositório é tipicamente tão fortemente conectada à lógica de negócios que isso pode ser integrado no mesmo repositório. Mas mesmo aí sua milhagem pode variar.

Obviamente, projetos simples que dificilmente mudam muito em termos de tecnologia ou suporte a várias pilhas, em que toda a interface do usuário pode ser hospedada na mesma fonte que o back-end e os serviços de back-end geralmente são usados ​​apenas pelo mesmo cliente, podem se beneficiar de mais repositórios fortemente integrados.

Nesse caso, você provavelmente ficaria bem em apenas ter a vertical completa em um repositório e se concentrar apenas em garantir que seus domínios funcionais sejam adequadamente independentes em seu próprio repositório. Você ainda tem muitas vantagens de repositórios menores e pouca sobrecarga caso contrário.

Arwin
fonte