A resposta aceita não "faz o Git " esquecer " um arquivo ..." (historicamente). Faz apenas o git ignorar o arquivo no presente / futuro.
Este método faz com que o git esqueça completamente os arquivos ignorados ( passado / presente / futuro), mas não exclui nada do diretório ativo (mesmo quando retirado novamente do controle remoto).
Este método requer o uso de /.git/info/exclude
(preferencial) OU um pré-existente .gitignore
em todas as confirmações que possuem arquivos a serem ignorados / esquecidos. 1
Todos os métodos de impor o git ignoram o comportamento depois que o fato reescreve o histórico e, portanto, têm ramificações significativas para quaisquer repositórios públicos / compartilhados / colaborativos que possam ser extraídos após esse processo. 2
Conselho geral: comece com um repositório limpo - tudo confirmado, nada pendente no diretório ou índice ativo e faça um backup !
Além disso, os comentários / histórico de revisões desta resposta ( e o histórico de revisões desta pergunta ) podem ser úteis / esclarecedores.
#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch
git add .gitignore
git commit -m "Create .gitignore"
#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached
#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --prune-empty flag in the following command
#this command must be run on each branch
git commit -m "ignored index"
#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits. If deliberate "empty" commits should be kept, remove --prune-empty and instead run git reset HEAD^ immediately after this command
git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all
#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch
git ls-files --other --ignored --exclude-standard
Por fim, siga o restante deste guia do GitHub (começando na etapa 6), que inclui avisos / informações importantes sobre os comandos abaixo .
git push origin --force --all
git push origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
Outros desenvolvedores que obtêm do repositório remoto modificado agora devem fazer um backup e, em seguida:
#fetch modified remote
git fetch --all
#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed
git reset FETCH_HEAD
Notas de rodapé
1 Como /.git/info/exclude
pode ser aplicado a todas as confirmações históricas usando as instruções acima, talvez os detalhes sobre a inserção de um .gitignore
arquivo nas confirmações históricas necessárias estejam além do escopo desta resposta. Eu queria que um apropriado .gitignore
estivesse no commit raiz, como se fosse a primeira coisa que fiz. Outros podem não se importar, pois /.git/info/exclude
podem realizar a mesma coisa, independentemente de onde .gitignore
exista no histórico de confirmação, e reescrever claramente o histórico é um assunto muito delicado, mesmo quando está ciente das ramificações .
FWIW, métodos potenciais podem incluir git rebase
ou um git filter-branch
que copia um externo .gitignore
para cada confirmação, como as respostas a esta pergunta
2 A imposição do comportamento do git ignore após a confirmação dos resultados de um git rm --cached
comando independente pode resultar na exclusão de arquivos recém-ignorados em futuras tentativas do controle remoto forçado. O --prune-empty
sinalizador no git filter-branch
comando a seguir evita esse problema removendo automaticamente a confirmação somente do índice "excluir todos os arquivos ignorados" anterior. Reescrever o histórico do git também altera os hashes de confirmação, o que causará estragos em futuras solicitações de repositórios públicos / compartilhados / colaborativos. Por favor, entenda as ramificações completamente antes de fazer isso em um repositório desse tipo. Este guia do GitHub especifica o seguinte:
Diga a seus colaboradores para refazer , e não mesclar, quaisquer ramificações que eles criaram do histórico de repositório antigo (contaminado). Um commit de mesclagem pode reintroduzir parte ou toda a história corrompida que você acabou de dar ao trabalho de eliminar.
Soluções alternativas que não afetam o repositório remoto são git update-index --assume-unchanged </path/file>
ou git update-index --skip-worktree <file>
, exemplos dos quais podem ser encontrados aqui .
git clean -X
parece semelhante, mas não se aplica a essa situação (quando os arquivos ainda estão sendo rastreados pelo Git). Estou escrevendo isso para quem procura uma solução para não seguir o caminho errado.