Não copie os arquivos, mescle os repositórios. O Git não faz grande diferença entre “repositório diferente” e “ramo diferente”. Mais precisamente, um repositório é uma coleção de tags e branches. Eu suponho que você queira mesclar o ramo mestre de todos os repositórios.
Abordagem geral (mas veja a discussão sobre git-subtree abaixo):
-
Pense no layout do seu monorepo. Presumo que, para o início, você terá cada repositório atual como uma subpasta do monorepo para evitar conflitos.
-
Para cada repositório atual, mova o conteúdo do repositório para uma subpasta e confirme a alteração. Você pode usar o comando
git mv
para fazer isso facilmente.Por exemplo se o seu componente é chamado
libfoo
e você atualmente tem esse layout de repositório:Makefile README.txt src/ ... include/ ...
Em seguida, podemos movê-lo para uma pasta
libfoo/
:libfoo/ Makefile README.txt src/ ... include/ ...
-
Crie um novo repositório para o seu monorepo e adicione todos os repos existentes como um "remoto". Apesar de seu nome, um repositório remoto pode ser um caminho para algum diretório no mesmo sistema de arquivos. Então,
git fetch --all
usa remotamente para carregar seu histórico no banco de dados git do monorepo. Depois, você pode listar todas as ramificações comgit branch --all
. Isso será parecido com:* master remotes/libfoo/master remotes/libbar/master ...
-
Para cada controle remoto, mescle seu ramo mestre. Não deve haver conflitos porque tudo está em um diretório separado.
-
Agora você terminou e você tem um monorepo sem perda de histórico. Você pode remover os controles remotos.
Mas cuidado: você só pode mesclar uma ramificação de cada repositório. Se um dos repositórios originais tiver vários ramos, eles não poderão mais ser mesclados sem conflitos excessivos. Considere reformulá-los depois de mover o conteúdo do repositório em uma pasta, mas antes de mesclar tudo no monorepo.
Na prática, você pode usar git subtree
para automatizar a maioria dessas etapas. O comando subtree permite que você mescle um ramo específico em um diretório específico.
- inicializa o monorepo e faz pelo menos um commit
-
para cada repositório existente, adicione-o como uma subárvore, por exemplo:
git subtree add -P libfoo/ ../path/to/libfoorepo master
O
-P
/--prefix
é o diretório sob o qual o conteúdo do repositório deve ser adicionado. No lugar do caminho para um repositório, qualquer URL de repositório pode ser usado. Por padrão, isso adicionará o histórico completo, ou você poderá--squash
do histórico em um único commit.
O Git-subtree é uma ferramenta extremamente poderosa para manipular monorepos. Você também pode extrair um diretório em um repositório separado ( git subtree push
) ou mesclar atualizações do repositório original ( git subtree pull
). Por exemplo, você pode usar isso para traduzir diferentes ramificações.
- Para traduzir uma ramificação
feature
: - Crie uma nova ramificação no monorepo:
git checkout -b feature
- Puxe as alterações do
feature
da libfoo para o diretório correto do monorepo:git subtree pull -P libfoo/ ../path/to/libfoorepo feature
. - Opcional: rebaixe o ramo para mestre para simplificar o gráfico do histórico.
Mas considere se um monorepo é realmente apropriado para seu caso de uso. Pode ainda ser desejável ter repositórios diferentes disponíveis independentemente. O contendor principal é git submodules, onde um repositório é montado como um subdiretório de outro. No entanto, a experiência não é perfeita. O histórico da ramificação não é compartilhado com o submódulo. Se você editar o código em um submódulo, terá que confirmar esse trabalho separadamente. Os submódulos Git são mais úteis para “vender” dependências externas que são fixadas em uma versão específica, não para desenvolvimento combinado.
Qualquer que seja a abordagem que você usar, os arquivos gitignore continuarão a funcionar, porque quaisquer padrões são correspondidos em relação ao arquivo gitignore. Um repositório pode conter vários arquivos gitignore.