Venho experimentando o uso da subárvore git e deparamos com a seguinte situação.
Usei a subárvore git para adicionar um projeto externo ao meu repositório, mantive intencionalmente todo o histórico do projeto upstream, pois quero poder me referir ao histórico do projeto e também contribuir com o projeto upstream posteriormente.
Acontece que outro colaborador do projeto upstream empurrou acidentalmente um arquivo grande para a ramificação principal. Para corrigir isso, o projeto upstream reescreveu o histórico e a força empurrada para o mestre. Ao criar meu "monorepo", incluí esse commit e também gostaria de removê-lo.
Como posso atualizar meu repositório para refletir o novo histórico da subárvore?
Minha primeira tentativa foi usar o branch-filter para remover completamente a subárvore e todo o histórico.
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD
Depois que a versão antiga da subárvore foi removida, pude adicionar novamente a subárvore usando o novo mestre upstream. No entanto, isso não funcionou porque, por algum motivo, o histórico de confirmação ainda aparece na saída do log do git.
Atualizar
Eu escrevi as etapas para criar um exemplo minimamente reproduzível.
Primeiro, crie um repositório git vazio.
git init test-monorepo cd ./test-monorepo
Crie uma confirmação inicial.
echo hello world > README git add README git commit -m 'initial commit'
Agora adicione uma subárvore para um projeto externo.
git remote add thirdparty [email protected]:teivah/algodeck.git git fetch thirdparty git subtree add --prefix algodeck thirdparty master
Faça alguns commits no monorepo
echo dont panic >> algodeck/README.md git commit -a -m 'test commit'
Agora tente usar o git filter-branch para remover a subárvore.
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
Examine a saída do log git, espero ver apenas meu commit inicial.
git log
git gc --prune=now
excluiria apenas confirmações que não aparecemgit log
?git log
, sem argumentos e ainda vejo os velhos compromissos.Respostas:
você já tem o mau commit em sua história e precisa se livrar dele antes de continuar
Vamos supor que você tenha
master
desviado o último commit e não tenha sido capaz de fazer mais nada (eu realmente não tenho suas filiais à vista, então preciso assumir algo para começar)você pode fazer o checkout do commit anterior e empurrar seu marcador de ramificação 1 passo para trás (ou X passos para trás), o que seria inofensivo em qualquer caso e, em seguida, puxe novamente
por exemplo
git checkout master~1
para finalizar o commit do pai do mestre, o git adverte que estamos fora dos ramosgit branch master -f
para forçar o checkout atual a se tornar mestre novamente, ou seja, na verdade, ele rebobina a ramificação principal para seu commit anterior (ou X commit anterior) e, a partir daqui, não importa se o upstream fez uma força ou não, podemos retomar normalmente, ou mesmo volte à etapa acima, se necessário, só podemos puxar o master novamente, sem perder nada do upstream (o que para nós também pode ser somente leitura, não pressionaremos nada por isso)git checkout master
para estar no nosso ramo principal "rebobinado", o mesmo commit em que estamos entrando, mas agora estar no ramogit pull
para puxar o mestre novamente (pode ser com ou sem--prune
), se desviado a montante, voltaremos à pista daqui, se não, obteremos o mesmo que tínhamos, se obtivemos o mesmo e não era suposto, talvez precisa voltar ao primeiro passo acima e retroceder mais confirmações, por exemplo,git checkout master~5
ou o que for (conforme necessário)fonte
git subtree
no seu repositório, limpe o histórico de confirmações para este controle remoto:
se uma das suas próprias confirmações tiver uma confirmação que inclua o arquivo grande, reescreva seu histórico para que esse arquivo grande não seja mais referenciado
Com essas duas etapas, o arquivo grande não será mais referenciado por nenhum commit no seu repositório.
Além disso, ele será excluído do disco rígido em algum momento, quando o git executar seu coletor de lixo e os atrasos na expiração dos blobs pendentes forem atingidos.
Se você tiver uma necessidade urgente de excluir esse grande arquivo o mais rápido possível do seu disco rígido:
Executar manualmente
fonte