Eu tenho um repositório Git que contém um número de subdiretórios. Agora, descobri que um dos subdiretórios não está relacionado ao outro e deve ser desanexado para um repositório separado.
Como posso fazer isso mantendo o histórico dos arquivos no subdiretório?
Acho que eu poderia criar um clone e remover as partes indesejadas de cada clone, mas suponho que isso me daria a árvore completa ao verificar uma revisão mais antiga etc. Isso pode ser aceitável, mas eu preferiria fingir que o dois repositórios não têm um histórico compartilhado.
Só para esclarecer, tenho a seguinte estrutura:
XYZ/
.git/
XY1/
ABC/
XY2/
Mas eu gostaria disso:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
git
git-subtree
git-filter-branch
matli
fonte
fonte
git filter-branch
minha resposta abaixo.Respostas:
Atualização : esse processo é tão comum que a equipe do git tornou muito mais simples com uma nova ferramenta
git subtree
,. Veja aqui: Desanexar (mover) o subdiretório em um repositório Git separadoVocê deseja clonar seu repositório e depois usá-lo
git filter-branch
para marcar tudo, exceto o subdiretório que você deseja que seu novo repositório seja coletado como lixo.Para clonar seu repositório local:
(Nota: o repositório será clonado usando links físicos, mas isso não é um problema, pois os arquivos vinculados não serão modificados por si mesmos - novos serão criados.)
Agora, vamos preservar os ramos interessantes que também queremos reescrever e remover a origem para evitar avançar até lá e garantir que os antigos commit não sejam referenciados pela origem:
ou para todas as ramificações remotas:
Agora você também pode remover tags que não têm relação com o subprojeto; você também pode fazer isso mais tarde, mas pode precisar podar seu repo novamente. Eu não fiz isso e recebi um
WARNING: Ref 'refs/tags/v0.1' is unchanged
para todas as tags (uma vez que não estavam relacionadas ao subprojeto); Além disso, após a remoção dessas tags, mais espaço será recuperado. Aparentemente,git filter-branch
deve ser possível reescrever outras tags, mas não foi possível verificar isso. Se você deseja remover todas as tags, usegit tag -l | xargs git tag -d
.Em seguida, use filter-branch e redefina para excluir os outros arquivos, para que possam ser removidos. Vamos adicionar também
--tag-name-filter cat --prune-empty
para remover confirmações vazias e reescrever tags (observe que isso terá que retirar sua assinatura):ou, como alternativa, reescrever apenas a ramificação HEAD e ignorar tags e outras ramificações:
Em seguida, exclua os reflogs de backup para que o espaço possa ser realmente recuperado (embora agora a operação seja destrutiva)
e agora você tem um repositório git local do subdiretório ABC com todo o histórico preservado.
Nota: Para a maioria dos usos,
git filter-branch
realmente deve ter o parâmetro adicionado-- --all
. Sim, é mesmo --space--all
. Esse precisa ser o último parâmetro para o comando. Como Matli descobriu, isso mantém os ramos e as tags do projeto incluídos no novo repositório.Edit: várias sugestões dos comentários abaixo foram incorporadas para garantir, por exemplo, que o repositório esteja realmente reduzido (o que nem sempre era o caso antes).
fonte
--no-hardlinks
? A remoção de um hardlink não afetará o outro arquivo. Objetos Git também são imutáveis. Somente se você alterar as permissões de proprietário / arquivo, precisará--no-hardlinks
.filter-branch
é--prune-empty
remover as confirmações agora vazias.-- --all
. Eu também corrigit remote rm origin
, egit tag -l | xargs git tag -d
antes dogit filter-branch
comando. Isso reduziu meu.git
diretório de 60M para ~ 300K. Observe que eu precisava executar esses dois comandos para obter a redução de tamanho.The Easy Way ™
Acontece que essa é uma prática tão comum e útil que os senhores superiores do Git tornaram muito fácil, mas você precisa ter uma versão mais recente do Git (> = 1.7.11 maio de 2012). Veja o apêndice para saber como instalar o Git mais recente. Além disso, há um exemplo do mundo real na explicação abaixo.
Prepare o repo antigo
Nota:
<name-of-folder>
NÃO deve conter caracteres iniciais ou finais. Por exemplo, a pasta denominadasubproject
DEVE ser passada comosubproject
, NÃO./subproject/
Nota para usuários do Windows: quando a profundidade da pasta for> 1,
<name-of-folder>
deve haver * separador de pastas no estilo nix (/). Por exemplo, a pasta denominadapath1\path2\subproject
DEVE ser passada comopath1/path2/subproject
Crie o novo repositório
Vincule o novo repositório ao GitHub ou a qualquer outro lugar
Limpeza interna
<big-repo>
, se desejadoNota : Isso deixa todas as referências históricas no repositório. Consulte o Apêndice abaixo se você estiver realmente preocupado em confirmar uma senha ou se precisar diminuir o tamanho do arquivo da sua
.git
pasta....
Passo a passo
Estas são as mesmas etapas acima , mas seguindo as etapas exatas para o meu repositório em vez de usar
<meta-named-things>
.Aqui está um projeto que tenho para implementar os módulos do navegador JavaScript no nó:
Quero dividir uma única pasta
btoa
,, em um repositório Git separadoAgora tenho uma nova ramificação,,
btoa-only
que só tem confirmaçõesbtoa
e quero criar um novo repositório.Em seguida, crio um novo repositório no GitHub ou Bitbucket, ou qualquer outra coisa e adiciono-o como
origin
Dia feliz!
Nota: Se você criou um repositório com a
README.md
,.gitignore
eLICENSE
, precisará puxar primeiro:Por fim, desejarei remover a pasta do repositório maior
...
Apêndice
Git mais recente no macOS
Para obter a versão mais recente do Git usando o Homebrew :
Últimas Git no Ubuntu
Se isso não funcionar (você tem uma versão muito antiga do Ubuntu), tente
Se isso ainda não funcionar, tente
Obrigado a rui.araujo pelos comentários.
Limpando seu histórico
Por padrão, remover arquivos do Git na verdade não os remove, apenas confirma que eles não estão mais lá. Se você realmente deseja remover as referências históricas (por exemplo, uma senha confirmada), é necessário fazer o seguinte:
Depois disso, você pode verificar se seu arquivo ou pasta não aparece mais no histórico do Git
No entanto, você não pode "empurrar" exclusões para o GitHub e similares. Se você tentar, receberá um erro e precisará fazê-
git pull
lo antes de podergit push
- e voltará a ter tudo no seu histórico.Portanto, se você deseja excluir o histórico da "origem" - ou seja, para excluí-lo do GitHub, Bitbucket, etc -, será necessário excluir o repositório e reenviar uma cópia removida do repositório. Mas espere - há mais ! - Se você estiver realmente preocupado em se livrar de uma senha ou algo parecido, precisará remover o backup (veja abaixo).
Fazendo
.git
menorO comando delete history mencionado acima ainda deixa para trás um monte de arquivos de backup - porque o Git é muito gentil em ajudá-lo a não arruinar seu repositório por acidente. Eventualmente, ele excluirá arquivos órfãos ao longo dos dias e meses, mas os deixará lá por um tempo, caso você perceba que excluiu acidentalmente algo que não queria.
Portanto, se você realmente quiser esvaziar o lixo para reduzir o tamanho do clone de um repositório imediatamente, precisará fazer todas essas coisas realmente estranhas:
Dito isso, eu recomendaria não executar essas etapas, a menos que você saiba que precisa - apenas no caso de remover o subdiretório errado, sabe? Os arquivos de backup não devem ser clonados quando você envia o repositório, eles estarão apenas na sua cópia local.
Crédito
fonte
git subtree
ainda faz parte da pasta 'contrib' e não está instalado por padrão em todas as distros. github.com/git/git/blob/master/contrib/subtreepopd
epushd
comando make este em vez implícita e mais difícil de grok o que pretende fazer ...A resposta de Paul cria um novo repositório contendo / ABC, mas não remove / ABC de dentro de / XYZ. O comando a seguir removerá / ABC de / XYZ:
Obviamente, teste-o primeiro no repositório 'clone --no-hardlinks' e siga-o com os comandos reset, gc and prune que Paul lista.
fonte
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ABC" --prune-empty HEAD
e será muito mais rápido. O filtro de índice funciona no índice, enquanto o filtro de árvore precisa fazer o checkout e preparar tudo para cada confirmação .--index-filter
método, convém fazer issogit rm -q -r -f
, para que cada invocação não imprima uma linha para cada arquivo excluído.Descobri que, para excluir corretamente o histórico antigo do novo repositório, você precisa fazer um pouco mais de trabalho após a
filter-branch
etapa.Faça o clone e o filtro:
Remova todas as referências ao histórico antigo. "Origin" estava acompanhando seu clone e "original" é onde o ramo de filtro salva o material antigo:
Mesmo agora, seu histórico pode estar preso em um pacote que o fsck não toca. Rasgue-o em pedaços, criando um novo pacote e excluindo os objetos não utilizados:
Há uma explicação disso no manual para filtro-ramificação .
fonte
git gc --aggressive --prune=now
ainda falta alguma coisa , não é?git gc --aggressive --prune=now
reduziu muito do novo repoEditar: script Bash adicionado.
As respostas dadas aqui funcionaram apenas parcialmente para mim; Muitos arquivos grandes permaneceram no cache. O que finalmente funcionou (depois de horas no #git no freenode):
Com as soluções anteriores, o tamanho do repositório era de cerca de 100 MB. Este reduziu para 1,7 MB. Talvez ajude alguém :)
O seguinte script bash automatiza a tarefa:
fonte
Isso não é mais tão complexo que você pode simplesmente usar o comando git filter-branch em um clone de seu repositório para selecionar os subdiretórios que você não deseja e depois enviar para o novo controle remoto.
fonte
The result will contain that directory (and only that) as its project root.
e, de fato, é isso que você obterá, ou seja, a estrutura original do projeto não é preservada.Atualização : O módulo git-subtree foi tão útil que a equipe do git o colocou no núcleo e o criou
git subtree
. Veja aqui: Desanexar (mover) o subdiretório em um repositório Git separadogit-subtree pode ser útil para isso
http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (descontinuado)
http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/
fonte
Aqui está uma pequena modificação para CoolAJ86 's 'A maneira fácil ™' resposta , a fim de dividir várias sub-pastas (digamos que
sub1
esub2
) em um novo repositório git.The Easy Way ™ (várias subpastas)
Prepare o repo antigo
Nota:
<name-of-folder>
NÃO deve conter caracteres iniciais ou finais. Por exemplo, a pasta denominadasubproject
DEVE ser passada comosubproject
, NÃO./subproject/
Nota para usuários do Windows: quando a profundidade da pasta for> 1,
<name-of-folder>
deve haver * separador de pastas no estilo nix (/). Por exemplo, a pasta denominadapath1\path2\subproject
DEVE ser passada comopath1/path2/subproject
. Além disso, não use omv
comando, masmove
.Nota final: a única e grande diferença com a resposta base é a segunda linha do script "
git filter-branch...
"Crie o novo repositório
Vincule o novo repositório ao Github ou a qualquer outro lugar
Limpeza, se desejado
Nota : Isso deixa todas as referências históricas no repositório. Consulte o Apêndice na resposta original se você estiver realmente preocupado em confirmar uma senha ou se precisar diminuir o tamanho do arquivo da sua
.git
pasta.fonte
sub1
esub2
pastas não existir com a versão inicial, tive de modificar meu--tree-filter
script como segue:"mkdir <name-of-folder>; if [ -d sub1 ]; then mv <sub1> <name-of-folder>/; fi"
. Para o segundofilter-branch
comando, substituí <sub1> por <sub2>, omiti a criação de <name-of-folder> e incluí-f
depoisfilter-branch
para substituir o aviso de um backup existente.A pergunta original quer que XYZ / ABC / (* arquivos) se torne ABC / ABC / (* arquivos). Depois de implementar a resposta aceita para meu próprio código, notei que ele realmente altera XYZ / ABC / (* arquivos) para ABC / (* arquivos). A página do manual filter-branch até diz:
Em outras palavras, promove a pasta de nível superior "acima" de um nível. Essa é uma distinção importante porque, por exemplo, na minha história eu havia renomeado uma pasta de nível superior. Ao promover pastas "para cima" em um nível, o git perde a continuidade no commit onde eu renomeei.
Minha resposta para a pergunta é fazer 2 cópias do repositório e excluir manualmente as pastas que você deseja manter em cada uma. A página de manual me apóia com isso:
fonte
targetdir
tenha sido renomeada em algum momento egit filter-branch
simplesmente encerrada, excluindo todos os commits feitos antes da renomeação! Chocante, considerando o quão hábil no Git é rastrear essas coisas e até mesmo a migração de partes de conteúdo individuais!git rm
leva vários argumentos, então não há nenhuma razão para executá-lo para cada arquivo / pasta:BYEBYE="dir/subdir2 dir2 file1 dir/file2"; git filter-branch -f --index-filter "git rm -q -r -f --cached --ignore-unmatch $BYEBYE" --prune-empty -- --all
Para adicionar à resposta de Paulo , descobri que, para recuperar o espaço, preciso enviar o HEAD para um repositório limpo e reduzir o tamanho do diretório .git / objects / pack.
ie
Após a remoção do gc, faça também:
Então você pode fazer
e o tamanho do ABC / .git é reduzido
Na verdade, algumas das etapas demoradas (por exemplo, git gc) não são necessárias com o push para limpar o repositório, ou seja:
fonte
A maneira correta agora é a seguinte:
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
Agora o GitHub ainda tem um pequeno artigo sobre esses casos.
Mas lembre-se de clonar seu repositório original primeiro para separar o diretório (pois isso excluiria todos os arquivos e outros diretórios e você provavelmente precisará trabalhar com eles).
Portanto, seu algoritmo deve ser:
git filter-branch
apenas arquivos à esquerda sob algum subdiretório, pressione para o novo controle remotofonte
Parece que a maioria (todas?) Das respostas aqui se baseiam em alguma forma
git filter-branch --subdirectory-filter
e no seu tipo. Isso pode funcionar "na maioria das vezes", no entanto, em alguns casos, por exemplo, quando você renomeou a pasta, por exemplo:Se você usar um estilo de filtro git normal para extrair "move_me_renamed", perderá o histórico de alterações no arquivo que ocorreu de volta quando era move_this_dir ( ref ).
Parece, portanto, que a única maneira de realmente manter todo o histórico de alterações (se o seu for um caso como esse) é, em essência, copiar o repositório (criar um novo repositório, definir isso como a origem) e, em seguida, destruir tudo o mais e renomeie o subdiretório para o pai desta maneira:
git branch -a
git checkout --track origin/branchABC
cp -r oldmultimod simple
cd simple
git rm otherModule1 other2 other3
git mv moduleSubdir1/* .
rmdir moduleSubdir1
git status
git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
git remote -v
git push
git checkout branch2
A seguir, o documento do github "Dividindo uma subpasta em um novo repositório" etapas 6 a 11 para enviar o módulo para um novo .
Isso não poupará espaço na pasta .git, mas preservará todo o histórico de alterações desses arquivos, mesmo com as renomeações. E isso pode não valer a pena se não houver "muita" história perdida, etc. Mas pelo menos você tem a garantia de não perder compromissos antigos!
fonte
Eu recomendo o guia do GitHub para dividir subpastas em um novo repositório . Os passos são semelhantes à resposta de Paulo , mas achei as instruções mais fáceis de entender.
Modifiquei as instruções para que elas se apliquem a um repositório local, em vez de um hospedado no GitHub.
fonte
If you create a new clone of the repository, you won't lose any of your Git history or changes when you split a folder into a separate repository.
Ainda de acordo com os comentários de todas as respostas aqui,filter-branch
osubtree
script resulta na perda de histórico onde quer que um subdiretório tenha sido renomeado. Existe algo que possa ser feito para resolver isso?Ao rodar
git filter-branch
usando uma versão mais recente dogit
(2.22+
talvez?), Ele diz para usar esta nova ferramenta git-filter-repo . Essa ferramenta certamente simplificou as coisas para mim.Filtrando com filtro-repositório
Comandos para criar o
XYZ
repositório a partir da pergunta original:suposições: * o repo XYZ remoto era novo e vazio antes do envio
Filtragem e movimentação
No meu caso, eu também queria mover alguns diretórios para uma estrutura mais consistente. Inicialmente, executei esse
filter-repo
comando simples seguido degit mv dir-to-rename
, mas descobri que poderia obter um histórico um pouco "melhor" usando a--path-rename
opção Em vez de ver a última modificação5 hours ago
nos arquivos movidos no novo repositório, agora vejolast year
(na interface do usuário do GitHub), que corresponde aos horários modificados no repositório original.Ao invés de...
Eu finalmente corri ...
Notas:git filter-repo --subdirectory-filter dir-matching-new-repo-name
). Esse comando converteu corretamente esse subdiretório na raiz do repositório local copiado, mas também resultou em um histórico de apenas as três confirmações necessárias para criar o subdiretório. (Eu não tinha percebido que isso--path
podia ser especificado várias vezes; portanto, evitando a necessidade de criar um subdiretório no repositório de origem.) Como alguém havia se comprometido com o repositório de origem no momento em que percebi que não havia conseguido levar adiante o histórico, eu apenas useigit reset commit-before-subdir-move --hard
após oclone
comando e adicionei--force
aofilter-repo
comando para fazê-lo operar no clone local ligeiramente modificado.git
, mas no final das contas eu clonei o git-filter-repo e o vinculei a$(git --exec-path)
:fonte
filter-repo
ferramenta (que apresentei no mês passado em stackoverflow.com/a/58251653/6309 )git-filter-repo
definitivamente deve ser a abordagem preferida neste momento. É muito, muito mais rápido e mais seguro do quegit-filter-branch
, e as salvaguardas contra muitas das dicas que podemos encontrar ao reescrever a história do Git. Esperamos que esta resposta receba mais atenção, já que é a única a ser abordadagit-filter-repo
.Eu tinha exatamente esse problema, mas todas as soluções padrão baseadas no ramo de filtro git eram extremamente lentas. Se você tem um pequeno repositório, isso pode não ser um problema, foi para mim. Escrevi outro programa de filtragem git baseado no libgit2 que, como primeiro passo, cria ramificações para cada filtragem do repositório primário e as envia para limpar repositórios como a próxima etapa. No meu repositório (500Mb 100000 confirma) os métodos padrão de ramificação de filtro git levavam dias. Meu programa leva alguns minutos para fazer a mesma filtragem.
Tem o nome fabuloso de git_filter e mora aqui:
https://github.com/slobobaby/git_filter
no GitHub.
Espero que seja útil para alguém.
fonte
Use este comando de filtro para remover um subdiretório, preservando suas tags e ramificações:
fonte
Para o que vale a pena, aqui está como usar o GitHub em uma máquina Windows. Digamos que você tenha um repositório clonado em residir em
C:\dir1
. A estrutura de diretórios parecida com esta:C:\dir1\dir2\dir3
. Odir3
diretório é o que eu quero ser um novo repositório separado.Github:
MyTeam/mynewrepo
Prompt do Bash:
$ cd c:/Dir1
$ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
Retornado:
Ref 'refs/heads/master' was rewritten
(fyi: dir2 / dir3 faz distinção entre maiúsculas e minúsculas.)$ git remote add some_name [email protected]:MyTeam/mynewrepo.git
git remote add origin etc
. não funcionou, retornou "remote origin already exists
"$ git push --progress some_name master
fonte
Como mencionei acima , eu tive que usar a solução reversa (excluir todos os commits que não tocassem no meu
dir/subdir/targetdir
), que parecia funcionar muito bem, removendo cerca de 95% dos commits (conforme desejado). Há, no entanto, dois pequenos problemas restantes.PRIMEIRO ,
filter-branch
fez um excelente trabalho ao remover confirmações que introduzem ou modificam código, mas aparentemente as confirmações de mesclagem estão abaixo de sua estação no Gitiverse.Esta é uma questão cosmética com a qual eu provavelmente posso viver (ele diz ... recuando lentamente com os olhos desviados) .
SEGUNDO, os poucos commits remanescentes são praticamente TODOS duplicados! Parece que adquiri uma segunda linha do tempo redundante que abrange quase toda a história do projeto. O interessante (que você pode ver na foto abaixo) é que meus três ramos locais não estão todos na mesma linha do tempo (que é, certamente, por que ele existe e não é apenas lixo coletado).
A única coisa que posso imaginar é que uma das confirmações excluídas foi, talvez, a confirmação de mesclagem única que
filter-branch
realmente foi excluída e que criou a linha do tempo paralela à medida que cada vertente agora imersa tirava sua própria cópia das confirmações. ( encolhe os ombros Onde está o meu TARDiS?) Tenho certeza de que posso resolver esse problema, embora eu realmente amo a entender como isso aconteceu.No caso do louco mergefest-O-RAMA, provavelmente deixarei esse em paz, já que ele se firmou tão firmemente na minha história de comprometimento - ameaçador para mim sempre que eu chego perto -, não parece estar realmente causando quaisquer problemas não cosméticos e porque é bastante bonito no Tower.app.
fonte
A maneira mais fácil
git splits
. Eu o criei como uma extensão git, com base na solução de jkeating .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 XY1 XY2
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
git splits
)Você pode precisar de algo como "git reflog expire --expire = now --all" antes da coleta de lixo para realmente limpar os arquivos. O git filter-branch apenas remove as referências no histórico, mas não remove as entradas de reflog que mantêm os dados. Claro, teste isso primeiro.
Meu uso de disco caiu drasticamente ao fazer isso, embora minhas condições iniciais fossem um pouco diferentes. Talvez --subdirectory-filter negue essa necessidade, mas duvido.
fonte
Confira o projeto git_split em https://github.com/vangorra/git_split
Transforme diretórios git em seus próprios repositórios em seu próprio local. Nenhum negócio engraçado de subárvore. Esse script pega um diretório existente no seu repositório git e o transforma em um repositório independente próprio. Ao longo do caminho, ele copiará todo o histórico de alterações do diretório que você forneceu.
fonte
Coloque isso no seu gitconfig:
fonte
Tenho certeza de que a subárvore git é ótima e maravilhosa, mas meus subdiretórios do código gerenciado pelo git que eu queria mover estavam todos em eclipse. Portanto, se você estiver usando o egit, é dolorosamente fácil. Pegue o projeto que você deseja mover e equipe-> desconecte-o e depois equipe-> compartilhe-o no novo local. O padrão é tentar usar o local do repositório antigo, mas você pode desmarcar a seleção existente e usar o novo local para movê-lo. Todos saúdam egit.
fonte
Você pode facilmente experimentar o https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/
Isso funcionou para mim. Os problemas que enfrentei nas etapas descritas acima são
neste comando
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
oBRANCH-NAME
é mestrese a última etapa falhar ao confirmar devido a um problema de proteção, siga - https://docs.gitlab.com/ee/user/project/protected_branches.html
fonte
Eu encontrei uma solução bastante direta, a idéia é copiar o repositório e remover a parte desnecessária. É assim que funciona:
1) Clone um repositório que você deseja dividir
2) Mover para a pasta git
2) Remova pastas desnecessárias e confirme
3) Remova o (s) histórico (s) de pastas desnecessárias com o BFG
4) Verifique se o histórico não contém os arquivos / pastas que você acabou de excluir
5) Agora você tem um repositório limpo, sem ABC, então basta empurrá-lo para uma nova origem
É isso aí. Você pode repetir as etapas para obter outro repositório,
basta remover XY1, XY2 e renomear XYZ -> ABC na etapa 3
fonte