Confirmei acidentalmente um arquivo indesejado ( filename.orig
enquanto resolvia uma mesclagem) no meu repositório há vários commits atrás, sem que eu o notasse até agora. Eu quero excluir completamente o arquivo do histórico do repositório.
É possível reescrever o histórico de alterações, que filename.orig
nunca foi adicionado ao repositório em primeiro lugar?
git
git-filter-branch
git-rewrite-history
git-rm
Grant Limberg
fonte
fonte
Respostas:
Por favor, não use esta receita se a sua situação não for a descrita na pergunta. Esta receita é para corrigir uma mesclagem incorreta e reproduzir suas confirmações boas em uma mesclagem fixa.
Embora
filter-branch
faça o que você deseja, é um comando bastante complexo e eu provavelmente escolheria fazer issogit rebase
. Provavelmente é uma preferência pessoal.filter-branch
pode fazê-lo em um único comando um pouco mais complexo, enquanto arebase
solução está executando as operações lógicas equivalentes uma etapa de cada vez.Experimente a seguinte receita:
(Observe que na verdade você não precisa de uma ramificação temporária, você pode fazer isso com um 'HEAD desanexado', mas é necessário anotar o ID de confirmação gerado pela
git commit --amend
etapa para fornecer aogit rebase
comando em vez de usar a ramificação temporária nome.)fonte
git rebase -i
seria mais rápido e fácil? $ git rebase -i <sh1-of-merge> Marque o correto como "edit" $ git rm somefile.orig vez que eu fiz isso. Provavelmente falta alguma coisa.git rebase -i
é muito útil, especialmente quando você tem várias operações de rebase-y para executar, mas é uma dor certa descrever com precisão quando você não está realmente apontando por cima do ombro de alguém e pode ver o que ele está fazendo com o editor. Eu uso o vim, mas nem todo mundo ficaria feliz com: "ggjcesquash <Esc> jddjp: wq" e instruções como "Mova a linha superior para depois da segunda linha atual e altere a primeira palavra na linha quatro para 'editar' agora salve e sair rapidamente parece mais complexo do que as etapas reais. Você normalmente acaba com algumas ações--amend
e--continue
também.Introdução: Você tem 5 soluções disponíveis
O pôster original declara:
Existem várias maneiras de remover completamente o histórico de um arquivo do git:
No caso do pôster original, alterar o commit não é realmente uma opção por si só, já que ele fez vários commit adicionais depois, mas por uma questão de completude, também explicarei como fazê-lo, para qualquer pessoa que apenas deseje alterar seu commit anterior.
Observe que todas essas soluções envolvem alterar / reescrever o histórico / confirmações de uma maneira ou outra, portanto, qualquer pessoa com cópias antigas das confirmações precisará fazer um trabalho extra para sincronizar novamente sua história com a nova história.
Solução 1: Alterando confirmações
Se você acidentalmente fez uma alteração (como adicionar um arquivo) no commit anterior e não deseja mais que o histórico dessa alteração exista, basta alterar o commit anterior para remover o arquivo:
Solução 2: reinicialização total (possivelmente mais uma rebase)
Como a solução 1, se você apenas deseja se livrar do seu commit anterior, também tem a opção de fazer uma redefinição definitiva do pai:
Esse comando reinicializará sua ramificação para o 1º compromisso pai anterior .
No entanto , se, como o pôster original, você fez várias confirmações após a confirmação em que deseja desfazer a alteração, ainda é possível usar redefinições rígidas para modificá-la, mas isso também envolve o uso de uma nova base. Aqui estão as etapas que você pode usar para alterar um commit mais adiante no histórico:
Solução 3: Rebase não interativo
Isso funcionará se você quiser remover completamente uma confirmação do histórico:
Solução 4: rebotes interativos
Esta solução permitirá que você realize o mesmo que as soluções nº 2 e nº 3, ou seja, modifique ou remova confirmações mais antigas do que a confirmação imediatamente anterior, de modo que a solução que você escolher usar depende de você. Os rebotes interativos não são adequados para refazer centenas de confirmações, por motivos de desempenho, portanto, eu usaria os rebotes não interativos ou a solução de ramificação do filtro (veja abaixo) nesses tipos de situações.
Para iniciar o rebase interativo, use o seguinte:
Isso fará com que o git rebobine o histórico de consolidação novamente para o pai da consolidação que você deseja modificar ou remover. Em seguida, ele apresentará uma lista dos commit rebobinados na ordem inversa, independentemente do editor que o git estiver configurado para usar (este é o Vim por padrão):
A confirmação que você deseja modificar ou remover estará no topo desta lista. Para removê-lo, basta excluir sua linha na lista. Caso contrário, substitua "pegar" com "editar" no 1 st linha, assim:
Em seguida, insira
git rebase --continue
. Se você optou por remover o commit por completo, então tudo o que você precisa fazer (além da verificação, consulte a etapa final desta solução). Se, por outro lado, você quiser modificar o commit, o git reaplicará o commit e pausará o rebase.Neste ponto, você pode remover o arquivo e alterar a confirmação e, em seguida, continue a nova atualização:
É isso aí. Como etapa final, se você modificou a confirmação ou a removeu completamente, é sempre uma boa ideia verificar se nenhuma outra alteração inesperada foi feita em sua ramificação, diferenciando-a do estado anterior à rebase:
Solução 5: filtrando ramificações
Por fim, essa solução é melhor se você deseja eliminar completamente todos os vestígios da existência de um arquivo do histórico, e nenhuma das outras soluções é adequada à tarefa.
Isso removerá
<file>
de todas as confirmações, iniciando na confirmação raiz. Se, em vez disso, você deseja apenas reescrever o intervalo de confirmaçãoHEAD~5..HEAD
, pode passar isso como um argumento adicional parafilter-branch
, como apontado nesta resposta :Novamente, após a
filter-branch
conclusão, geralmente é uma boa idéia verificar se não há outras alterações inesperadas diferenciando sua ramificação com seu estado anterior antes da operação de filtragem:Alternativa para ramificação de filtro: BFG Repo Cleaner
Ouvi dizer que a ferramenta BFG Repo Cleaner é executada mais rapidamente do que
git filter-branch
, portanto, convém verificar isso como uma opção. É até mencionado oficialmente na documentação da ramificação do filtro como uma alternativa viável:Recursos adicionais
fonte
filter-branch
causa recalcular de hashes? Se uma equipe trabalha com um repositório em que um arquivo grande deve ser filtrado, como eles fazem isso para que todos terminem com o mesmo estado do repositório?Se você não cometeu nada desde então, apenas
git rm
o arquivo egit commit --amend
.Se você tem
passará por cada alteração de
merge-point
paraHEAD
, excluir filename.orig e reescrever a alteração. Usar--ignore-unmatch
significa que o comando não falhará se, por algum motivo, filename.orig estiver ausente de uma alteração. Essa é a maneira recomendada na seção Exemplos na página do manual git-filter-branch .Nota para usuários do Windows: O caminho do arquivo deve usar barras
fonte
git-filter-branch
parece dar a primeira.filter-branch
"
e não'
ao usar o Windows, ou você receberá um erro de "revisão ruim", sem ajuda.Esta é a melhor maneira:
http://github.com/guides/completely-remove-a-file-from-all-revisions
Apenas certifique-se de fazer backup das cópias dos arquivos primeiro.
EDITAR
Infelizmente, a edição de Neon foi rejeitada durante a revisão.
Veja a publicação de Neons abaixo, pode conter informações úteis!
Por exemplo, para remover todos os
*.gz
arquivos acidentalmente confirmados no repositório git:Isso ainda não funcionou para mim? (Atualmente, estou na versão 1.7.6.1 do git)
Não sei por que, já que eu só tinha UM ramo principal. Enfim, finalmente consegui meu repositório git realmente limpo, inserindo um novo repositório vazio e vazio, por exemplo,
(sim!)
Então eu clonei isso em um novo diretório e movi a pasta .git para este. por exemplo
(sim! finalmente limpo!)
Depois de verificar se está tudo bem, você pode excluir os diretórios
../large_dot_git
e../tmpdir
(talvez daqui a algumas semanas ou meses, apenas no caso ...)fonte
--prune-empty
ao comando filter-branch.Reescrever o histórico do Git exige a alteração de todos os IDs de confirmação afetados, para que todos que estão trabalhando no projeto precisem excluir suas cópias antigas do repositório e fazer um novo clone depois de limpar o histórico. Quanto mais pessoas incomodar, mais você precisará de um bom motivo para fazê-lo - seu arquivo supérfluo não está realmente causando um problema, mas se você estiver trabalhando no projeto, poderá limpar o histórico do Git, se quiser para!
Para torná-lo o mais fácil possível, recomendo o uso do BFG Repo-Cleaner , uma alternativa mais simples e rápida para o
git-filter-branch
projetado especificamente para remover arquivos do histórico do Git. Uma maneira de facilitar a sua vida aqui é que ele realmente lida com todos os árbitros por padrão (todas as tags, ramificações etc.), mas também é 10 - 50x mais rápido.Você deve seguir cuidadosamente as etapas aqui: http://rtyley.github.com/bfg-repo-cleaner/#usage - mas o principal é exatamente isso: faça o download do jar BFG (requer Java 6 ou superior) e execute este comando :
Todo o histórico do repositório será verificado e qualquer arquivo nomeado
filename.orig
(que não esteja na sua confirmação mais recente ) será removido. Isso é consideravelmente mais fácil do que usargit-filter-branch
para fazer a mesma coisa!Divulgação completa: sou o autor do BFG Repo-Cleaner.
fonte
fonte
Apenas para adicionar isso à solução de Charles Bailey, eu apenas usei um git rebase -i para remover arquivos indesejados de um commit anterior e funcionou como um encanto. Os passos:
fonte
A maneira mais simples que encontrei foi sugerida por
leontalbot
(como comentário), que é um post publicado pela Anoopjohn . Eu acho que vale o seu próprio espaço como resposta:(Eu converti para um script bash)
Todos os créditos vão para
Annopjohn
eleontalbot
para apontar.NOTA
Esteja ciente de que o script não inclui validações; verifique se você não comete erros e se possui um backup caso algo dê errado. Funcionou para mim, mas pode não funcionar na sua situação. USE-O COM CUIDADO (siga o link se quiser saber o que está acontecendo).
fonte
Definitivamente,
git filter-branch
é o caminho a percorrer.Infelizmente, isso não será suficiente para remover completamente
filename.orig
do seu repositório, pois ainda pode ser referenciado por tags, entradas de reflog, controles remotos e assim por diante.Eu recomendo remover todas essas referências também e chamar o coletor de lixo. Você pode usar o
git forget-blob
script deste site para fazer tudo isso em uma única etapa.git forget-blob filename.orig
fonte
Se é o último commit que você deseja limpar, tentei com a versão 2.14.3 do git (Apple Git-98):
fonte
git reflog expire --expire=now --all; git gc --prune=now
é uma coisa muito ruim de se fazer. A menos que você está ficando sem espaço em disco, deixe lixo git recolher esses commits depois de algumas semanasFoi para isso que
git filter-branch
foi projetado.fonte
Você também pode usar:
git reset HEAD file/path
fonte