Dependências do Git e do projeto
Nicola Paolucci
Representante do desenvolvedor
Pense nas seguintes questões:
Como você lida com as dependências do projeto com o git
?
O projeto é composto por vários repositórios interdependentes. No momento, eles são gerenciados com svn:externals
. Qual é a melhor maneira de lidar com esse caso com o git
?
Como dividir um repositório muito grande em componentes menores usando o git
?
Essas são algumas das perguntas que a gente recebe com mais frequência.
O tópico parece ser um grande problema para muitas equipes de software que adotam o git
; portanto, neste artigo, vou tentar esclarecer o problema.
É óbvio que, as dependências do projeto e a infraestrutura de build são duas áreas interligadas e, mesmo dentro da Atlassian, foi iniciada uma discussão sobre o "Futuro dos builds".
Ter repositórios separados em vez de ter um único pode tornar algumas coisas mais difíceis. Mas é um passo natural em comparação e — às vezes obrigatório — na evolução de um projeto de software por pelo menos dois motivos principais: aumento dos tempos de compilação e compartilhamento de dependências entre projetos.
Pintura com traços amplos: diretrizes e soluções abaixo do ideal
Então, voltando à pergunta: Como você rastreia e gerencia as dependências do projeto com o git
?
Se for possível, não faça!
Brincadeiras à parte, deixe-me responder com traços amplos primeiro e ir mais fundo depois. Perceba que não há nenhuma bala de prata — no git
ou não — que vai resolver sem problemas todos os problemas relacionados às dependências do projeto.
Depois que um projeto cresce em um determinado tamanho, faz sentido que ele seja dividido em componentes lógicos, mas não espere ter mais de 100 milhões de linhas de código em um único repositório antes de fazer essa divisão. Portanto, a seguir estão apenas diretrizes para que você possa criar sua própria abordagem.
Material relacionado
Instalar o Git
VER SOLUÇÃO
Aprenda a usar o Git com o Bitbucket Cloud
Primeira opção: use uma ferramenta de compilação/dependência apropriada em vez do git
Uma ferramenta de gerenciamento de dependências é o meu caminho atual recomendado para lidar com as dores de crescimento e os tempos de compilação de projetos consideráveis.
Mantenha seus módulos separados em repositórios individuais e gerencie a interdependência usando uma ferramenta criada para o trabalho. Existe um para (quase) todas as pilhas de tecnologia existentes. Alguns exemplos:
- Maven (ou Gradle) se você usar Java
- npm para aplicativos de ponto central
- Bower, Component.io, etc. se você usa Javascript (atualizado!)
- Pip e requirements.txt se você usa Python
- RubyGems,Bundler se você usa Ruby
- NuGet para.NET
- Ivy (ou alguma ação personalizada do CMake) para C++ (atualizado!)
- Aplicativos CocoaPods para Cocoa iOS
- Composer ou Phing para PHP (adicionado!)
- Em Go, a infraestrutura do build/dependência é um pouco incorporada à linguagem (mas há gente trabalhando em uma solução mais completa. Consulte godep). Para o servidor Git (Bitbucket), a gente usa o Maven e o Bower. No momento da compilação, a ferramenta escolhida vai extrair as versões corretas das dependências para que seu projeto principal possa ser compilado. Algumas dessas ferramentas têm limitações e fazem suposições que não são ideais, mas são comprovadas e viáveis.
As dificuldades de dividir o projeto
No início de um projeto, a estrutura é simples, tudo é embalado em um único build. Mas, à medida que o projeto cresce, essa simplicidade pode resultar em seu build muito lento — nesse ponto você precisa de armazenamento em "cache," que é onde o gerenciamento de dependências entra em ação. Aliás, essa informação indica que os submódulos (veja abaixo) se prestam muito bem a linguagens dinâmicas, por exemplo. Em resumo, acho que a maioria das pessoas precisa se preocupar com os tempos de compilação em algum momento, e é por esse motivo que você deve usar uma ferramenta de gerenciamento de dependências.
Dividir componentes em repositórios separados traz muita dor. Em nenhuma ordem específica:
- Fazer uma alteração em um componente requer uma versão
- Leva tempo e pode falhar por vários motivos idiotas
- Parece idiota para pequenas mudanças
- Exige a configuração manual de novos builds para cada componente
- Dificulta a capacidade de descoberta dos repositórios
- Refatoramento quando nem toda a fonte está disponível em um único repositório
- Em algumas configurações (como essa), a atualização de APIs requer um lançamento marco do produto e, em seguida, o plug-in e, em seguida, o produto de novo. É provável que tenhamos esquecido alguma coisa, mas você entendeu. Uma solução perfeita para o problema está longe daqui.
Segunda opção: Usar o submódulo git
Se você não pode ou não quer usar uma ferramenta de dependência, o git
tem uma facilidade para lidar com submódulos
. Os submódulos podem ser convenientes, em particular para linguagens dinâmicas. No entanto, eles não vão sempre salvá-lo de tempos de compilação lentos. Já escrevi algumas diretrizes e dicas sobre elas e também explorei alternativas. A Internet em geral também tem argumentos contra eles.
Correspondência 1:1 entre svn:external e git
MAS! Se você está procurando uma correspondência 1-para-1 entre svn:externals
e git,
você precisa usar submódulos
garantindo que os submódulos
rastreiem apenas branches de lançamento e não commits aleatórios.
Terceira opção: usar outras ferramentas de dependência de build e pilha cruzada
Nem sempre você vai desfrutar de um projeto uniforme no total e que pode ser construído e montado com uma única ferramenta. Por exemplo, alguns projetos móveis vão precisar manipular as dependências Java e C++ ou usar ferramentas proprietárias para gerar ativos. Para essas situações mais complexas, você pode aprimorar o git
com uma camada extra no topo. Um ótimo exemplo nessa área é o repositório do Android.
Outras ferramentas de build que valem a pena explorar:
Conclusão e leituras adicionais
Sugestões de leitura sobre a infraestrutura de build (e Maven) de Charles O'Farrell:
- Em busca da melhor ferramenta de build
- E o acompanhamento do Maven é defeituoso por padrão
- Maven recursivo considerado prejudicial
Gostaria de concluir com esta excelente citação do último artigo acima. Mesmo que seja sobre o Maven, ele também pode ser aplicado a outras ferramentas de build e dependência:
"Um cache não faz nada além de acelerar as coisas. Você poderia remover um cache por completo e o sistema circundante funcionaria da mesma forma, apenas com mais lentidão. Um cache também não tem efeitos colaterais. Não importa o que você tenha feito com um cache no passado, uma determinada consulta ao cache vai devolver o mesmo valor para a mesma consulta no futuro.
A experiência do Maven é muito diferente do que eu descrevo! Os repositórios Maven são usados como caches, mas sem ter as propriedades dos caches. Quando você pede algo de um repositório Maven, é muito importante o que você fez no passado. Ele retorna a coisa mais recente que você colocou nele. Pode até falhar, se você pedir algo antes de colocar."
Compartilhar este artigo
Próximo tópico
Leitura recomendada
Marque esses recursos para aprender sobre os tipos de equipes de DevOps ou para obter atualizações contínuas sobre DevOps na Atlassian.