Esta questão é baseada no subdiretório Desanexar em um repositório Git separado
Em vez de desanexar um único subdiretório, quero desanexar alguns. Por exemplo, minha árvore de diretórios atual se parece com isso:
/apps
/AAA
/BBB
/CCC
/libs
/XXX
/YYY
/ZZZ
E eu gostaria disso:
/apps
/AAA
/libs
/XXX
O --subdirectory-filter
argumento para git filter-branch
não funcionar porque se livra de tudo, exceto do diretório especificado na primeira vez em que é executado. Eu pensei que usar o --index-filter
argumento para todos os arquivos indesejados funcionaria (embora seja entediante), mas se eu tentar executá-lo mais de uma vez, recebo a seguinte mensagem:
Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f
Alguma ideia? TIA
fonte
--tag-name-filter cat
aos seus parâmetrosEtapas manuais com comandos simples do git
O plano é dividir diretórios individuais em seus próprios repositórios e depois mesclá-los. As etapas manuais a seguir não empregaram scripts geek-to-use, mas comandos fáceis de entender e podem ajudar a mesclar N subpastas extras em outro repositório único.
Dividir
Vamos supor que seu repo original seja: original_repo
1 - Aplicativos divididos:
2 - Bibliotecas divididas
Continue se você tiver mais de 2 pastas. Agora você deve ter dois repositórios git novos e temporários.
Conquiste mesclando aplicativos e bibliotecas
3 - Prepare o novo repositório:
E você precisará fazer pelo menos um commit. Se as três linhas a seguir forem ignoradas, seu primeiro repo aparecerá imediatamente abaixo da raiz do repo:
Com o arquivo temporário confirmado, o
merge
comando na seção posterior será interrompido conforme o esperado.Partindo do feedback do usuário, em vez de adicionar um arquivo aleatório como
a_file_and_make_a_commit
, você pode optar por adicionar um.gitignore
, ouREADME.md
etc.4 - Mesclar aplicativos repo primeiro:
Agora você deve ver o diretório de aplicativos dentro do seu novo repositório.
git log
deve mostrar todas as mensagens de confirmação históricas relevantes.Nota: como Chris observou abaixo nos comentários, para a versão mais recente (> = 2.9) do git, é necessário especificar
--allow-unrelated-histories
comgit merge
5 - Mesclar repositório de libs a seguir da mesma maneira:
Continue se você tiver mais de 2 repositórios para mesclar.
Referência: Mesclar um subdiretório de outro repositório com o git
fonte
.gitignore
eREADME.md
arquiva.git merge .. git read-tree
etapa, pois os registra como arquivos adicionados recentemente e todos os meus git guis não fazem a conexão com os commits anteriores.Por que você quer correr
filter-branch
mais de uma vez? Você pode fazer tudo de uma só vez, portanto, não é necessário forçá-lo (observe que você precisaextglob
habilitar no seu shell para que isso funcione):Isso deve livrar-se de todas as alterações nos subdiretórios indesejados e manter todas as suas ramificações e confirmações (a menos que elas afetem apenas os arquivos nos subdiretórios removidos, em virtude de
--prune-empty
) - sem problemas com confirmações duplicadas etc.Após esta operação, os diretórios indesejados serão listados como não rastreados por
git status
.O
$(ls ...)
necessárioextglob
é avaliado pelo seu shell em vez do filtro de índice, que usa osh
builtineval
(ondeextglob
não está disponível). Consulte Como habilito as opções de shell no git? para mais detalhes sobre isso.fonte
git
comandos e, portanto, não é tão suscetível a diferenças na maneira como als
interpretação é interpretada nos sistemas operacionais, como a @Bae descobriu.Respondendo a minha própria pergunta aqui ... depois de muitas tentativas e erros.
Consegui fazer isso usando uma combinação de
git subtree
egit-stitch-repo
. Estas instruções são baseadas em:Primeiro, peguei os diretórios que queria manter em seu próprio repositório separado:
Criei um novo repositório vazio e importei / costurei os dois últimos nele:
Isso cria dois ramos,
master-A
emaster-B
, cada um segurando o conteúdo de um dos repos costurados. Para combiná-los e limpar:Agora não tenho muita certeza de como / quando isso acontece, mas após o primeiro
checkout
e opull
, o código se funde magicamente no ramo mestre (qualquer percepção sobre o que está acontecendo aqui é apreciada!)Tudo parece ter funcionado conforme o esperado, exceto que, se eu examinar o
newRepo
histórico de consolidação, haverá duplicatas quando o conjunto de alterações afetou tantoapps/AAA
elibs/XXX
. Se houver uma maneira de remover duplicatas, seria perfeito.fonte
export PERL5LIB="$PERL5LIB:/usr/local/git/lib/perl5/site_perl/"
à minha configuração do bash para encontrar o Git.pm. Então eu instalei com cpan.git subtree add
para executar esta tarefa. Veja stackoverflow.com/a/58253979/1894803Eu escrevi um filtro git para resolver exatamente esse problema. Ele tem o nome fantástico de git_filter e está localizado no github aqui:
https://github.com/slobobaby/git_filter
É baseado no excelente libgit2.
Eu precisava dividir um repositório grande com muitos commits (~ 100000) e as soluções baseadas no ramo de filtro git levaram vários dias para serem executadas. O git_filter leva um minuto para fazer a mesma coisa.
fonte
Use a extensão git 'git splits'
git splits
é um script bash que é um wrappergit branch-filter
que eu criei como uma extensão git, com base na solução do jkeating .Foi feito exatamente para esta situação. Para o seu erro, tente usar a
git splits -f
opção para forçar a remoção do backup. Comogit splits
opera em uma nova ramificação, ela não reescreverá sua ramificação atual; portanto, o backup é estranho. Consulte o leia-me para obter mais detalhes e use-o em uma cópia / clone do seu repositório (apenas no caso!) .git splits
.Dividir os diretórios em uma ramificação local
#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ apps/AAA libs/ZZZ
Crie um repositório vazio em algum lugar. Vamos assumir que criamos um repositório vazio chamado
xyz
no GitHub que possui o caminho:[email protected]:simpliwp/xyz.git
Envie para o novo repositório.
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz [email protected]:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master
Clone o repositório remoto recém-criado em um novo diretório local
#change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone [email protected]:simpliwp/xyz.git
fonte
fonte
for
circuito vale a pena reconhecer, uma vez que outras respostas semelhantes não incluí-lo. Se você não tiver uma cópia local de cada ramificação no seu clone,filter-branch
não as contabilizará como parte de sua reescrita, o que poderia excluir os arquivos introduzidos em outras ramificações, mas ainda não foram mesclados à sua ramificação atual. (Apesar de ser também vale a pena fazer umgit fetch
em quaisquer ramos você já verificados para garantir que eles permaneçam atual.)Uma solução fácil: git-filter-repo
Eu tive um problema semelhante e, depois de revisar as várias abordagens listadas aqui, descobri o git-filter-repo . É recomendado como uma alternativa ao git-filter-branch na documentação oficial do git aqui .
Para criar um novo repositório a partir de um subconjunto de diretórios em um repositório existente, você pode usar o comando:
Filtre vários arquivos / pastas encadeando-os:
Portanto, para responder à pergunta original , com o git-filter-repo, você precisaria apenas do seguinte comando:
fonte
Sim. Forçar a substituição do backup usando o
-f
sinalizador nas chamadas subseqüentesfilter-branch
para substituir esse aviso. :) Caso contrário, acho que você tem a solução (ou seja, erradique um diretório indesejado de cada vezfilter-branch
).fonte
Exclua o backup presente no diretório .git em refs / original como a mensagem sugere. O diretório está oculto.
fonte