Estamos desenvolvendo projetos, mas reutilizamos muito código entre os projetos e temos muitas bibliotecas que contêm nosso código comum. À medida que implementamos novos projetos, encontramos mais maneiras de fatorar o código comum e colocá-lo nas bibliotecas. As bibliotecas dependem umas das outras e os projetos dependem das bibliotecas. Cada projeto e todas as bibliotecas usadas nesse projeto precisam usar a mesma versão de todas as bibliotecas às quais estão se referindo. Se lançarmos um software, teremos que corrigir bugs e talvez adicionar novos recursos por muitos anos, às vezes por décadas. Temos cerca de uma dúzia de bibliotecas, as mudanças geralmente abrangem mais de duas e várias equipes trabalham em vários projetos em paralelo, fazendo alterações simultâneas em todas essas bibliotecas.
Recentemente, mudamos para o git e configuramos repositórios para cada biblioteca e cada projeto. Usamos o stash como um repositório comum, fazemos novas coisas nas ramificações de recursos, fazemos solicitações pull e as mesclamos somente após a revisão.
Muitos dos problemas com os quais lidamos nos projetos exigem que façamos alterações em várias bibliotecas e no código específico do projeto. Isso geralmente inclui alterações nas interfaces da biblioteca, algumas das quais são incompatíveis. (Se você acha que isso soa suspeito: fazemos interface com hardware e ocultamos hardware específico por trás de interfaces genéricas. Quase sempre que integramos o hardware de algum outro fornecedor, nos deparamos com casos que nossas interfaces atuais não antecipavam e, portanto, precisamos refiná-las.) exemplo, imagine um projeto P1
usando as bibliotecas L1
, L2
e L3
. L1
também usa L2
e L3
, e L2
usa L3
também. O gráfico de dependência é assim:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Agora imagine que um recurso para este projeto exija alterações P1
e as L3
quais alterem a interface do L3
. Agora adicione projetos P2
e P3
à mistura, que também se referem a essas bibliotecas. Não podemos nos permitir mudar todos eles para a nova interface, executar todos os testes e implantar o novo software. Então, qual é a alternativa?
- implementar a nova interface em
L3
- faça uma solicitação de
L3
recebimento e aguarde a revisão - mesclar a mudança
- crie uma nova versão do
L3
- comece a trabalhar no recurso
P1
, fazendo com que ele se refira aoL3
novo lançamento, e implemente o recurso naP1
ramificação do recurso - faça uma solicitação pull, revise-a e mesclada
(Eu notei que eu esqueci de mudar L1
e L2
para a nova versão. E eu nem sei onde enfiar isso no, porque ele teria que ser feito em paralelo com P1
...)
Esse é um processo tedioso, propenso a erros e muito longo para implementar esse recurso, requer análises independentes (o que torna muito mais difícil a revisão), não é escalável e provavelmente nos afastará dos negócios porque ficamos tão atolados no processo que nunca fazemos nada.
Mas como empregamos ramificação e marcação para criar um processo que nos permita implementar novos recursos em novos projetos sem muita sobrecarga?
Respostas:
Tipo de colocar o óbvio aqui, mas talvez valha a pena mencionar.
Geralmente, os repositórios git são personalizados por lib / projeto porque tendem a ser independentes. Você atualiza seu projeto e não se importa com o resto. Outros projetos, dependendo dele, simplesmente atualizarão sua biblioteca sempre que entenderem.
No entanto, seu caso parece altamente dependente de componentes correlacionados, de modo que um recurso geralmente afeta muitos deles. E o todo deve ser empacotado como um pacote. Como a implementação de um recurso / alteração / bug geralmente requer adaptação de diferentes bibliotecas / projetos ao mesmo tempo, talvez faça sentido colocá-los todos no mesmo repositório.
Existem fortes vantagens / desvantagens nisso.
Vantagens:
Desvantagens:
Cabe a você saber se o preço vale o benefício.
EDITAR:
Funcionaria assim:
feature_x
feature_y
e tambémfeature_z
pode ter sido adicionada. Torna-se uma mesclagem "entre equipes". É por isso que é uma desvantagem séria.Apenas para constar: acho que essa é, na maioria dos casos, uma péssima idéia e deve ser feita com cautela, porque a desvantagem da mesclagem geralmente é maior do que a obtida com o gerenciamento de dependências / rastreamento adequado de recursos.
fonte
:-/
Além disso, mesmo aqueles que são (e que pressionaram pela mudança para o git), não sabem como ajustar nosso processo de desenvolvimento ao git. Suspiro. Receio que sejam alguns meses difíceis, até que as coisas comecem a ficar mais suaves. Obrigado de qualquer maneira, a sua é a resposta mais / única útil até agora.A solução que você procura é uma ferramenta de gerenciamento de dependência em coordenação com os submódulos git
Ferramentas como:
Você pode usar essas ferramentas para definir dependências de um projeto.
Você pode exigir que um submódulo seja pelo menos versão > 2.xx ou denotar um intervalo de versões compatíveis = 2.2. * Ou menor que uma versão específica <2.2.3
Sempre que você libera uma nova versão de um dos pacotes, pode identificá-lo com o número da versão, dessa forma, pode inserir essa versão específica do código em todos os outros projetos.
fonte
Submodules
Você deve tentar git submódulos , como sugerido em um comentário.
Quando projeto
P1
refere-se aos três sub-módulosL1
,L2
eL3
, na verdade ele armazena uma referência ao commits particulares em todos os três repositórios: esses são os que trabalham versões de cada bibliotecas para esse projeto .Portanto, vários projetos podem trabalhar com vários submódulos:
P1
podem se referir à versão antiga da bibliotecaL1
enquanto o projetoP2
usou a nova versão.O que acontece quando você entrega uma nova versão do
L3
?L3
L2
trabalhos comL3
, confirmar, ...L1
trabalhos com novasL2
, ...P1
funciona com as novas versões de todas as bibliotecas:P1
da cópia de trabalho local deL1
,L2
eL3
, fetche as mudanças que você está interessado.git add L1 L2 L3
confirmar a nova referência aos módulosP1
, teste, revisão, solicitação de extração, mesclagem ...Metodologia
Sim, requer análises independentes, porque você altera:
Você ficaria fora do negócio por entregar lixo? (Talvez não, na verdade). Se sim, você precisa executar testes e revisar as alterações.
Com as ferramentas git apropriadas (par
gitk
), você pode ver facilmente quais versões das bibliotecas cada projeto usa e pode atualizá-las independentemente, de acordo com suas necessidades. Os submódulos são perfeitos para a sua situação e não atrasam o processo.Talvez você possa encontrar uma maneira de automatizar parte desse processo, mas a maioria das etapas acima requer cérebros humanos. A maneira mais eficaz de reduzir o tempo seria garantir que suas bibliotecas e projetos sejam fáceis de evoluir. Se a sua base de código puder lidar com novos requisitos normalmente, as revisões de código serão mais simples e levarão pouco do seu tempo.
(Editar) Outra coisa que pode ajudá-lo é agrupar revisões de código relacionadas. Você confirma todas as alterações e aguarda até propagá-las para todas as bibliotecas e projetos que as usam antes de submeter solicitações pull (ou antes de cuidar delas). Você acaba fazendo uma revisão maior para toda a cadeia de dependências. Talvez isso ajude você a economizar tempo se cada alteração local for pequena.
fonte
Então, o que eu entendo é que, para P1, você deseja alterar a interface L3, mas deseja que os outros P2 e P3, que dependem da interface L3, sejam alterados imediatamente. Este é um caso típico de compatibilidade com versões anteriores. Há um bom artigo sobre Preservando a compatibilidade com versões anteriores
Existem várias maneiras de resolver isso:
OU
fonte
Se estou acertando seu problema:
Portanto, o objetivo é fazer P1 e L1 de uma só vez e, um mês depois, L2 e L3 de outra.
No mundo Java, isso é trivial e talvez a maneira padrão de trabalhar:
Portanto, você pode ter o código no disco local do L3 que não seria compilado se estivesse compilando com a cópia do P1 no outro diretório do disco; felizmente, não está fazendo isso. O Java pode fazer isso diretamente porque os contos de compilação / vinculação são colocados em arquivos jar compilados, não no código-fonte.
Não conheço uma solução amplamente usada preexistente para esse problema para o mundo C / C ++, e imagino que você não queira mudar de idioma. Mas algo pode ser facilmente hackeado com arquivos make que fazem o equivalente:
Você pode até usar o suporte a C / C ++ no maven , embora a maioria dos desenvolvedores de C olhe para você de forma estranha, se você o fizer ...
fonte
:)
Existe uma solução simples: cortar ramificações de lançamento em todo o repositório, mesclar todas as correções para todos os lançamentos enviados ativamente (é fácil em casos claros deve ser possível no git).
Todas as alternativas criarão uma bagunça horrível ao longo do tempo e com o crescimento do projeto.
fonte