Subárvore Git: a alternativa ao submódulo Git

A Internet está repleta de artigos sobre por que você não deve usar os submódulos do Git. Embora os submódulos sejam úteis para alguns casos de uso, eles têm várias desvantagens.
Existem alternativas? A resposta é: sim! Existem (pelo menos) duas ferramentas que podem ajudar a rastrear o histórico de dependências de software em seu projeto, permitindo que você continue usando o Git:
Subárvore do GitRepositório do Google
Nesta publicação, a gente vai analisar o git subtree e mostrar por que é uma melhoria em relação ao submódulo do Git (embora não seja perfeita).
O que é git subtree e por que devo usar?
O git subtree permite aninhar o repositório dentro de outro como um subdiretório. É uma das várias maneiras pelas quais os projetos Git podem gerenciar as dependências do projeto.

Por que você pode querer considerar o git subtree
O gerenciamento de um fluxo de trabalho simples é fácil.
As versões mais antigas do Git são suportadas (ainda mais antigas que a v1.5.2).
O código do subprojeto está disponível logo após a conclusão do clone do superprojeto.
O
git subtreenão exige que os usuários do repositório aprendam nada de novo. Eles podem ignorar o fato de que você está usando umgit subtreepara gerenciar dependências.git subtreenão adiciona novos arquivos de metadados como o submódulo do Git (por exemplo, .gitmodule).O conteúdo do módulo pode ser modificado sem ter uma cópia separada do repositório da dependência em outro lugar.
Desvantagens (mas, em nossa opinião, são aceitáveis):
Você deve aprender uma nova estratégia de merge (
git subtree).Contribuir com o código de volta para os subprojetos é um pouco mais complicado.
A responsabilidade de não misturar o código do superprojeto e do subprojeto nos commits é sua.
Como usar o git subtree
O git subtree está disponível na versão stock do Git desde maio de 2012 — v1.7.11 e superior. A versão instalada pelo Homebrew no OSX já tem uma subtree conectada, mas, em algumas plataformas, você pode precisar seguir as instruções de instalação.
Deixe-me mostrar o exemplo canônico de rastreamento de um plugin do Vim usando o git subtree.
O caminho rápido e sujo sem rastreamento remoto
Se você quiser apenas alguns forros para cortar e colar, basta ler este parágrafo. Primeiro, adicione git subtree em uma pasta de prefixo especificada:
git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash(A prática comum é não armazenar todo o histórico do subprojeto no repositório principal, mas se você quiser que ele seja preservado, basta omitir a marcação –squash.)
O comando acima produz esta saída:
git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git main
warning: no common commits
remote: Counting objects: 338, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 338 (delta 101), reused 323 (delta 89)
Receiving objects: 100% (338/338), 71.46 KiB, done.
Resolving deltas: 100% (101/101), done.
From https://bitbucket.org/vim-plugins-mirror/vim-surround.git
* branch main -} FETCH_HEAD
Added dir '.vim/bundle/tpope-vim-surround'Como você pode ver, essa ação registra um merge commit ao condensar todo o histórico do repositório vim-surround em um:
1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci]
ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci]Se depois de um tempo você quiser atualizar o código do plugin do repositório upstream, você pode fazer um git subtree pull:
git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squashÉ muito rápido e tranquilo, mas os comandos são um pouco longos e difíceis de lembrar. Podemos tornar os comandos mais curtos adicionando o subprojeto como um controle remoto.
Adicionando o subprojeto como um controle remoto
Adicionar a subárvore como um controle remoto nos permite consultá-la de forma mais curta:
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.gitAgora podemos adicionar a subárvore (como antes), mas agora podemos nos referir ao controle remoto de forma resumida:
git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squashO comando para atualizar o subprojeto posteriormente se torna:
git fetch tpope-vim-surround main
git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squashContribuindo de volta ao upstream
Agora a gente tem liberdade para fazer o commit das correções para o subprojeto no diretório de trabalho local. Quando é hora de contribuir de volta para o projeto upstream, precisamos bifurcar o projeto e adicioná-lo como outro controle remoto:
git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.gitAgora podemos usar o comando subtree push como o seguinte:
git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround main
git push using: durdn-vim-surround main
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 308 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To ssh://git@bitbucket.org/durdn/vim-surround.git
02199ea..dcacd4b dcacd4b21fe51c9b5824370b3b224c440b3470cb -} mainDepois disso, estamos prontos e podemos abrir um pull request para o mantenedor do pacote.
Posso fazer a mesma coisa sem usar o comando git subtree?
Sim! Sim, você pode. O git subtree é diferente da estratégia de merge de subárvore. Você ainda pode usar a estratégia de merge, mesmo que por algum motivo o git subtree não esteja disponível. Veja como:
Adicione a dependência como um simples git remote:
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.gitAntes de ler o conteúdo da dependência no repositório, é importante gravar um merge para que possamos rastrear todo o histórico da árvore do plug-in até este ponto:
git merge -s ours --no-commit tpope-vim-surround/mainQuais saídas:
Automatic merge went well; stopped before committing as requestedEm seguida, lemos o conteúdo do objeto de árvore mais recente no repositório de plugins no diretório de trabalho pronto para o commit:
git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/mainAgora podemos fazer o commit (e vai ser um commit de merge que vai preservar o histórico da árvore que lemos):
git ci -m"[subtree] adding tpope-vim-surround"
[stree 779b094] [subtree] adding tpope-vim-surroundQuando for atualizar o projeto, agora é possível extrair usando a estratégia de merge de git subtree:
git pull -s subtree tpope-vim-surround mainO git subtree é uma excelente alternativa
Depois de usar submódulos do Git por um tempo, você vai perceber que git subtree resolve muitos problemas. Como de costume, com todas as coisas do Git, há uma curva de aprendizado para aproveitar ao máximo a função.
Consulte este artigo sobre o poder do Git subtree.