Dividindo um subdiretório com submódulos em um repositório Git separado
-
25-09-2019 - |
Pergunta
Como um subconjunto da pergunta destacar-subdirectory Já foi feita antes e considerando o fato de que, embora muitas perguntas tenham sido feitas sobre o processo de dividir e mesclar repositórios Git, não consegui encontrar um que toca o assunto de dividir quando os submódulos estão presentes.
Então, no seguinte cenário:
.git/
.gitmodules
folder/
data/
content/
other_data/
submoduleA/
submoduleB/
Eu gostaria de obter dois repositórios com a seguinte estrutura:
.git/
data/
e
.git/
.gitmodules
content/
other_data/
submoduleA/
submoduleB/
O primeiro caso não é um problema e pode ser resolvido facilmente com o método descrito em destacar-subdirectory.
O segundo não tanto. A existência de submódulos e o fato de que .gitmodules contém o caminho completo para folder/content/submoduleA
e folder/content/submoduleB
faz parte da história ser inconsistente, pois .gitmodules refere-se a uma estrutura de diretório inexistente (uma vez que o ramo de filtro é usado).
Então, eu gostaria de saber se existe uma maneira de fazer isso sem causar história inconsistente.
Solução
Eu suspeito (não testado) que um segundo git filter-branch
teria a oportunidade de modificar o .gitmodules
Conteúdo para cada compromisso do novo repo.
Mas na verdade um git submodule split
O comando estava em discussão no início de 2009.
Uso proposto:
git submodule split [--url submodule_repo_url] submodule_dir \
[alternate_dir...]
Substituir
submodule_dir
com um submódulo recém-criado, mantendo toda a história desubmodule_dir
.
Este comando também reescreve cada compromisso na história do repositório atual para incluir a revisão correta desumodule_dir
e o apropriado.gitmodules
entradas.
No entanto, eu não vejo isso no mais recente o que está cozinhando.
O script no patch proposto pode lhe dar uma idéia do tipo de reescrita de árvores necessária para atualizar o .gitmodules
Arquivo embora.
Outras dicas
Eu tive exatamente o mesmo problema que o Unode e consegui resolvê -lo com o seguinte procedimento:
git clone git@github.com:kdeldycke/kev-code.git
cd kev-code
git filter-branch --tree-filter "test -f ./.gitmodules && mv ./.gitmodules ./cool-cavemen/gitmodules || echo 'No .gitmodules file found'" -- --all
git filter-branch --force --prune-empty --subdirectory-filter cool-cavemen --tag-name-filter cat -- --all init..HEAD
git filter-branch --force --tree-filter "test -f ./gitmodules && mv ./gitmodules ./.gitmodules || echo 'No gitmodules file found'" -- --all
git filter-branch --force --tree-filter "test -f ./.gitmodules && sed -i 's/cool-cavemen\///g' ./.gitmodules || echo 'No .gitmodules file found'" -- --all
git remote rm origin
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
git remote add origin git@github.com:kdeldycke/cool-cavemen.git
git push -u origin master --force --tags
Como você vê, o truque é renomear temporariamente o .gitmodules
arquivo e uso sed
Para reescrever seu conteúdo. Você pode obter todos os detalhes e o Contexto deste procedimento no meu blog.
Para elaborar a resposta de Kevin: supondo que nenhum submódulo jamais existisse lá fora cool/cavemen
- A pasta que está sendo destacada (caso contrário, uma edição mais elaborada de .gitmodules será necessária para remover essas seções extras), isso pode ser alcançado Muito de mais rápido e em uma etapa usando um index-filter
:
$ git filter-branch --subdirectory-filter cool/cavemen --index-filter $'
hash=$(git rev-parse --verify $GIT_COMMIT:.gitmodules 2>/dev/null) &&
git update-index --add --cacheinfo 100644 $(git cat-file -p $hash |
sed \'s/cool\\/cavemen\\///g\' | git hash-object -w --stdin) .gitmodules ||
true' --tag-name-filter cat --prune-empty -- --all
Como um benefício adicional, se cool/cavemen
não existia em todas cool/cavemen
será analisado.
Se for esse o caso, você pode executar o seguinte para remover referências inalteradas:
$ git for-each-ref --format='%(refname)' |
grep -vF "$(git for-each-ref --format='%(refname)' refs/original |
sed 's/refs\/original\///g')" | xargs -n 1 git update-ref -d