Ocasionalmente, eu soltava um DVD-rip em um projeto de site, então descuidadamente git commit -a -m ...
e, zap, o repositório foi inchado por 2,2 shows. Na próxima vez que fiz algumas edições, excluí o arquivo de vídeo e confirmei tudo, mas o arquivo compactado ainda está lá no repositório, no histórico.
Eu sei que posso iniciar ramificações a partir dessas confirmações e refazer uma ramificação para outra. Mas o que devo fazer para mesclar as duas confirmações para que o arquivo grande não apareça no histórico e seja limpo no procedimento de coleta de lixo?
git
version-control
git-rebase
git-rewrite-history
culebrón
fonte
fonte
git filter-branch
, mas achei o oposto verdadeiro.Respostas:
Use o BFG Repo-Cleaner , uma alternativa mais simples e rápida para o
git-filter-branch
projetado especificamente para remover arquivos indesejados do histórico do Git.Siga cuidadosamente as instruções de uso , a parte principal é exatamente isso:
Todos os arquivos com mais de 100 MB de tamanho (que não estão no seu commit mais recente ) serão removidos do histórico do seu repositório Git. Você pode usar
git gc
para limpar os dados mortos:O BFG é geralmente pelo menos 10-50x mais rápido que a execução
git-filter-branch
e geralmente mais fácil de usar.Divulgação completa: sou o autor do BFG Repo-Cleaner.
fonte
git push --force
após as etapas, caso contrário, o repo remoto ainda não foi alterado.git push --force
. Também digno de nota: forçar push pode não ser permitido pelo controle remoto (gitlab.com não, por padrão. Tinha que "desproteger" a ramificação).O que você quer fazer é altamente perturbador se você tiver publicado o histórico para outros desenvolvedores. Consulte "Recuperando da Rebase Upstream" na
git rebase
documentação para obter as etapas necessárias após reparar seu histórico.Você tem pelo menos duas opções:
git filter-branch
e um rebase interativo, ambos explicados abaixo.Usando
git filter-branch
Eu tive um problema semelhante com dados volumosos de teste binário de uma importação do Subversion e escrevi sobre a remoção de dados de um repositório git .
Digamos que seu histórico do git seja:
Observe que
git lola
é um alias não padrão, mas altamente útil. Com a--name-status
opção, podemos ver modificações na árvore associadas a cada confirmação.No commit "descuidado" (cujo nome do objeto SHA1 é ce36c98), o arquivo
oops.iso
é o rasgo do DVD adicionado por acidente e removido no próximo commit, cb14efd. Usando a técnica descrita na postagem de blog acima mencionada, o comando a ser executado é:Opções:
--prune-empty
remove confirmações que ficam vazias ( ou seja , não alteram a árvore) como resultado da operação do filtro. No caso típico, esta opção produz um histórico mais limpo.-d
nomeia um diretório temporário que ainda não existe para usar na construção do histórico filtrado. Se você estiver executando em uma distribuição moderna do Linux, especificar uma árvore/dev/shm
resultará em uma execução mais rápida .--index-filter
é o evento principal e é executado no índice em cada etapa do histórico. Você deseja removeroops.iso
onde quer que seja encontrado, mas não está presente em todas as confirmações. O comandogit rm --cached -f --ignore-unmatch oops.iso
exclui o DVD-rip quando está presente e não falha caso contrário.--tag-name-filter
descreve como reescrever nomes de tags. Um filtro decat
é a operação de identidade. Seu repositório, como o exemplo acima, pode não ter nenhuma tag, mas eu incluí esta opção para generalidade total.--
especifica o final das opções paragit filter-branch
--all
a seguir--
é uma abreviação para todas as referências. Seu repositório, como a amostra acima, pode ter apenas uma referência (mestre), mas eu incluí esta opção para generalidade total.Depois de alguma agitação, a história é agora:
Observe que a nova confirmação "descuidado" é adicionada apenas
other.html
e que a confirmação "Remover DVD-rip" não está mais na ramificação principal. A ramificação rotuladarefs/original/refs/heads/master
contém as confirmações originais caso você cometa um erro. Para removê-lo, siga as etapas em "Lista de verificação para reduzir um repositório".Para uma alternativa mais simples, clone o repositório para descartar os bits indesejados.
O uso de um
file:///...
URL de clone copia objetos em vez de criar apenas links físicos.Agora sua história é:
Os nomes dos objetos SHA1 para as duas primeiras confirmações ("Índice" e "Página de administração") permaneceram os mesmos porque a operação de filtro não modificou essas confirmações. “Careless” perdido
oops.iso
e “página de login” tem um novo pai, para que seus SHA1s fez a mudança.Rebase interativo
Com um histórico de:
você deseja remover
oops.iso
do “Careless” como se nunca o tivesse adicionado e, em seguida, “Remove DVD-rip” é inútil para você. Portanto, nosso plano para uma reestruturação interativa é manter a "Página do administrador", editar "Descuidado" e descartar "Remover o rasgo do DVD".A execução
$ git rebase -i 5af4522
inicia um editor com o seguinte conteúdo.Executando nosso plano, modificamos para
Ou seja, excluímos a linha com “Remove DVD-rip” e alteramos a operação em “Careless” para
edit
melhor que parapick
.Ao sair do editor, a opção salvar é exibida no prompt de comando com a seguinte mensagem.
Como a mensagem nos diz, estamos no commit "descuidado" que queremos editar, então executamos dois comandos.
O primeiro remove o arquivo incorreto do índice. O segundo modifica ou altera “Careless” para ser o índice atualizado e
-C HEAD
instrui o git a reutilizar a antiga mensagem de confirmação. Por fim,git rebase --continue
prossegue com o restante da operação de rebase.Isso fornece um histórico de:
qual é o que você quer.
fonte
-f
(ou--force
) ao seugit push
comando: “Normalmente, o comando se recusa a atualizar uma ref remota que não é um ancestral da ref local usada para substituí-la. Este sinalizador desativa a verificação. Isso pode fazer com que o repositório remoto perca confirmações; use-o com cuidado. ”... "git rm --cached -rf --ignore-unmatch path/to/dir"...
Por que não usar este comando simples, mas poderoso?
A
--tree-filter
opção executa o comando especificado após cada checkout do projeto e, em seguida, confirma novamente os resultados. Nesse caso, você remove um arquivo chamado DVD-rip de todos os instantâneos, existindo ou não.Se você souber qual commit introduziu o arquivo enorme (por exemplo, 35dsa2), poderá substituir HEAD por 35dsa2..HEAD para evitar a reescrita de histórico demais, evitando assim confirmações divergentes, se você ainda não o enviou. Este comentário de cortesia de @ alpha_989 parece importante demais para ser deixado de lado aqui.
Veja este link .
fonte
fatal: bad revision 'rm'
que corrigi usando em"
vez de'
. Comando geral:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
commit
onde colocou o arquivo (digamos35dsa2
), poderá substituí-loHEAD
por35dsa2..HEAD
.tree-filter
é muito mais lentoindex-filter
que o normal e não tentará fazer check-out de todos os commits e reescrevê-los. se você usar HEAD, ele tentará fazer isso.(A melhor resposta que eu já vi para esse problema é: https://stackoverflow.com/a/42544963/714112 , copiada aqui, pois esse segmento aparece alto nos rankings de pesquisa do Google, mas o outro não.
🚀 Um one-liner shell incrivelmente rápido 🚀
Esse script de shell exibe todos os objetos de blob no repositório, classificados do menor para o maior.
Para o meu repositório de amostras, ele foi executado 100 vezes mais rápido que os outros encontrados aqui.
No meu confiável sistema Athlon II X4, ele lida com o repositório Linux Kernel com seus 5.622.155 objetos em pouco mais de um minuto .
O Script Base
Quando você executa o código acima, você obtém uma boa saída legível por humanos como esta:
🚀 Remoção rápida de arquivo 🚀
Suponha que você deseje remover os arquivos
a
e, ab
partir de cada confirmação acessívelHEAD
, você pode usar este comando:fonte
--tag-name-filter cat
para re-tag a nova commits correspondente como eles são reescritas, isto é,git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
(ver esta resposta relacionada )git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD
workorder direita da batgit rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Depois de tentar praticamente todas as respostas no SO, finalmente encontrei essa jóia que removeu e excluiu rapidamente os arquivos grandes do meu repositório e me permitiu sincronizar novamente: http://www.zyxware.com/articles/4027/how-to-delete -files-permanentemente do seu local e repositórios git remotos
CD na sua pasta de trabalho local e execute o seguinte comando:
substitua FOLDERNAME pelo arquivo ou pasta que você deseja remover do repositório git fornecido.
Feito isso, execute os seguintes comandos para limpar o repositório local:
Agora empurre todas as alterações no repositório remoto:
Isso limpará o repositório remoto.
fonte
Estes comandos funcionaram no meu caso:
É um pouco diferente das versões acima.
Para aqueles que precisam enviar isso para o github / bitbucket (eu só testei isso com o bitbucket):
fonte
git rm --cached files
. A proposta de Greg Bacon é mais completa, e é a mesma para esta mina, mas ele perdeu o índice --force para casos em que você usa o ramo de filtro por várias vezes, e ele escreveu tantas informações que minha versão é como resumo disso.-f
opção de não apenas-rf
aquigit rm --cached -rf --ignore-unmatch oops.iso
em vez degit rm --cached -r --ignore-unmatch oops.iso
como por @ lfender6445 abaixoApenas observe que esses comandos podem ser muito destrutivos. Se mais pessoas estiverem trabalhando no repositório, todas terão que puxar a nova árvore. Os três comandos do meio não são necessários se o seu objetivo NÃO é reduzir o tamanho. Como a ramificação do filtro cria um backup do arquivo removido e pode permanecer lá por um longo tempo.
fonte
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
em vez de primeiro do seu códigogit filter-branch --tree-filter 'rm -f path/to/file' HEAD
funcionou muito bem para mim, embora eu tenha encontrado o mesmo problema descrito aqui , que resolvi seguindo esta sugestão .O livro pro-git possui um capítulo inteiro sobre a reescrita do histórico - consulte a seção
filter-branch
/ Removendo um arquivo de cada confirmação .fonte
Se você sabe que seu commit foi recente, em vez de passar pela árvore inteira, faça o seguinte:
git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD
fonte
Encontrei isso com uma conta bitbucket, onde havia armazenado acidentalmente backups gigantescos * .jpa do meu site.
git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all
Altere
MY-BIG-DIRECTORY
o espaço para a pasta em questão para reescrever completamente seu histórico ( incluindo tags ).fonte: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/
fonte
Isso o removerá do seu histórico
fonte
Eu basicamente fiz o que estava nesta resposta: https://stackoverflow.com/a/11032521/1286423
(para histórico, copio e colo aqui)
Não deu certo, porque eu gosto de renomear e mudar muito as coisas. Então, algum arquivo grande estava em pastas que foram renomeadas, e acho que o gc não pôde excluir a referência a esses arquivos por causa da referência em
tree
objetos que apontam para esse arquivo. Minha solução definitiva para realmente matá-lo foi:Meu repositório (o
.git
) mudou de 32 MB para 388 KB, que nem mesmo a ramificação do filtro conseguiu limpar.fonte
git filter-branch
é um comando poderoso que você pode usá-lo para excluir um arquivo enorme do histórico de confirmações. O arquivo permanecerá por um tempo e o Git o removerá na próxima coleta de lixo. Abaixo está o processo completo de exclusão de arquivos do histórico de confirmação . Por segurança, o processo abaixo executa os comandos em uma nova ramificação primeiro. Se o resultado for o que você precisava, redefina-o novamente para o ramo que você realmente deseja alterar.fonte
Use Git Extensions , é uma ferramenta de interface do usuário. Ele possui um plug-in chamado "Localizar arquivos grandes", que localiza arquivos lage nos repositórios e permite removê-los permanentemente.
Não use 'git filter-branch' antes de usar esta ferramenta, pois ela não poderá encontrar arquivos removidos por 'filter-branch' (Altough 'filter-branch' não remove completamente os arquivos dos arquivos do pacote de repositório) .
fonte
Você pode fazer isso usando o
branch filter
comando:git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD
fonte
Existem respostas muito boas neste segmento, mas enquanto isso, muitas delas estão desatualizadas. O uso
git-filter-branch
não é mais recomendado, porque é difícil de usar e muito lento em grandes repositórios.git-filter-repo
é muito mais rápido e mais simples de usar.git-filter-repo
é um script Python, disponível no github: https://github.com/newren/git-filter-repo .Você precisa de apenas um arquivo: o script Python3 git-filter-repo. Copie-o para um caminho incluído na variável PATH. No Windows, pode ser necessário alterar a primeira linha do script (consulte INSTALL.md). Você precisa do Python3 instalado no seu sistema, mas isso não é grande coisa.
Primeiro você pode correr
Isso ajuda a determinar o que fazer em seguida.
Você pode excluir seu arquivo ripado de DVD em qualquer lugar:
Repositório de filtros é realmente rápido. Uma tarefa que levou cerca de 9 horas no meu computador por ramo de filtro, foi concluída em 4 minutos pelo repositório de filtro. Você pode fazer muito mais coisas legais com o repositório de filtros. Consulte a documentação para isso.
Aviso: Faça isso em uma cópia do seu repositório. Muitas ações do repositório de filtro não podem ser desfeitas. O repositório de filtros alterará os hashes de confirmação de todos os commits modificados (é claro) e todos os seus descendentes até os últimos commits!
fonte
Quando você se deparar com esse problema,
git rm
não será suficiente, pois o git lembra que o arquivo existia uma vez em nossa história e, portanto, manterá uma referência a ele.Para piorar as coisas, também não é fácil refazer o processo, porque quaisquer referências ao blob impedirão que o coletor de lixo git limpe o espaço. Isso inclui referências remotas e referências de reflog.
Eu montei
git forget-blob
, um pequeno script que tenta remover todas essas referências e, em seguida, usa o git filter-branch para reescrever todos os commit no branch.Depois que seu blob não for referenciado,
git gc
você se livrará deleO uso é bem simples
git forget-blob file-to-forget
. Você pode obter mais informações aquihttps://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/
Eu montei isso graças às respostas do Stack Overflow e a algumas entradas do blog. Créditos para eles!
fonte
Além de
git filter-branch
(solução lenta, mas pura de git) e BFG (mais fácil e muito eficiente), também há outra ferramenta para filtrar com bom desempenho:https://github.com/xoofx/git-rocket-filter
De sua descrição:
O objetivo do git-rocket-filter é semelhante ao comando
git-filter-branch
, fornecendo os seguintes recursos exclusivos:fonte