Remova arquivos sensíveis e seus compromissos do histórico Git
-
22-08-2019 - |
Pergunta
Eu gostaria de colocar um projeto Git no Github, mas ele contém certos arquivos com dados confidenciais (nomes de usuário e senhas, como /config/deploy.rb para capistrano).
Eu sei que posso adicionar esses nomes de arquivos a .gitignore, mas isso não removeria sua história no Git.
Também não quero começar de novo, excluindo o diretório /.git.
Existe uma maneira de remover tudo traços de um arquivo específico no seu histórico Git?
Solução
Para todos os propósitos práticos, o primeiro coisa com que você deve se preocupar é Alterando suas senhas! Não está claro em sua pergunta se o seu repositório Git é totalmente local ou se você ainda tem um repositório remoto em outro lugar; Se for remoto e não garantido de outras pessoas, você tem um problema. Se alguém clonou esse repositório antes de corrigir isso, terá uma cópia de suas senhas na máquina local e não há como forçá -las a atualizar para sua versão "fixada" com ela desaparecendo da história. A única coisa segura que você pode fazer é alterar sua senha para outra coisa em todos os lugares em que a usou.
Com isso fora do caminho, veja como consertá -lo. Github respondeu exatamente essa pergunta como uma FAQ:
Nota para usuários do Windows: Use citações duplas (") em vez de singles neste comando
git filter-branch --index-filter \
'git update-index --remove filename' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force
Lembre -se de que, depois de empurrar esse código para um repositório remoto como o Github e outros clonarem esse repositório remoto, agora você está em uma situação em que está reescrevendo o histórico. Quando outros tentam abaixar suas mudanças mais recentes depois disso, eles receberão uma mensagem indicando que as alterações não podem ser aplicadas porque não é uma avançada rápida.
Para consertar isso, eles terão que excluir seu repositório existente e recarregá-lo novamente, ou seguir as instruções em "recuperação de rebase a montante" no MANPAGE DE GIT-REBASE.
No futuro, se você acidentalmente comete algumas alterações com informações confidenciais, mas percebe antes da Empurrando para um repositório remoto, existem algumas correções mais fáceis. Se você se compromete a adicionar as informações confidenciais, basta remover as informações confidenciais e executar:
git commit -a --amend
Isso alterará o commit anterior com novas alterações que você fez, incluindo remoções de arquivos inteiras feitas com um git rm
. Se as alterações estiverem mais adiante na história, mas ainda não forem empurradas para um repositório remoto, você poderá fazer uma rebase interativa:
git rebase -i origin/master
Isso abre um editor com os compromissos que você fez desde o seu último ancestral comum com o repositório remoto. Mudar "Escolha" para "Editar" em qualquer linha que represente um commit com informações confidenciais e salve e saia. Git passará pelas mudanças e o deixará em um local onde puder:
$EDITOR file-to-fix
git commit -a --amend
git rebase --continue
Para cada alteração com informações confidenciais. Eventualmente, você acabará de volta em sua filial e poderá pressionar com segurança as novas alterações.
Outras dicas
Alterar suas senhas é uma boa ideia, mas para o processo de remoção de senha da história do seu repo, recomendo o BFG Repo-Cleaner, uma alternativa mais rápida e simples a git-filter-branch
Projetado explicitamente para remover dados privados de repositórios Git.
Crie um private.txt
Listagem de arquivos As senhas, etc, que você deseja remover (uma entrada por linha) e, em seguida, execute este comando:
$ java -jar bfg.jar --replace-text private.txt my-repo.git
Todos os arquivos sob um tamanho limite (1 MB por padrão) na história do seu repo serão digitalizados e qualquer string correspondente (que não está no seu Mais recentes comprometimento) será substituído pela string "*** removido ***". Você pode então usar git gc
Para limpar os dados mortos:
$ git gc --prune=now --aggressive
O BFG é tipicamente 10-50x mais rápido do que a execução git-filter-branch
E as opções são simplificadas e adaptadas em torno desses dois casos de uso comuns:
- Removendo Arquivos grandes loucos
- Removendo Senhas, credenciais & outro Dados privados
Divulgação completa: sou o autor do BFG Repo-Cleaner.
Eu recomendo Este script Por David Underhill, trabalhou como um encanto para mim.
Ele adiciona esses comandos, além disso, o ramo de filtro de Natacado para limpar a bagunça que deixa para trás:
rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
Script completo (todo o crédito para David Underhill)
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune
Os dois últimos comandos podem funcionar melhor se alterados para o seguinte:
git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
Se você pressionou para o Github, o empurrão de força não é suficiente, exclua o repositório ou o suporte de contato
Mesmo se você forçar o empurrão um segundo depois, isso não é suficiente como explicado abaixo.
Os únicos cursos de ação válidos são:
O que vazou é uma credencial mutável como uma senha?
- Sim: modifique suas senhas imediatamente e considere usar mais chaves OAuth e API!
Não (fotos nuas):
Você se importa se todos os problemas do repositório são nucleosos?
- Não: exclua o repositório
sim:
- suporte de contato
- Se o vazamento for muito crítico para você, a ponto de você estar disposto a obter algum tempo de inatividade do repositório para tornar menos provável que vaze, Torne -o privado Enquanto você espera o apoio do Github para responder a você
Força empurrar um segundo depois não é suficiente porque:
O Github continua pendurado por muito tempo.
A equipe do Github tem o poder de excluir esse compromisso pendurado, se você os entrar em contato.
Eu experimentei isso em primeira mão quando Enviou todos os e -mails do GitHub para um repositório Eles me pediram para derrubá -lo, então eu fiz, e eles fizeram um
gc
. Puxe solicitações que contêm os dados tem que ser excluído no entanto: que os dados do Repo permaneceram acessíveis até um ano após a queda inicial devido a isso.Dernling Commites podem ser vistos através de:
- A interface da web commit: https://github.com/cirosantilli/test-dangling/commit/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Wayback Machine)
- A API: https://api.github.com/repos/cirosantilli/test-dangling/commits/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Wayback Machine)
Uma maneira conveniente de obter a fonte nesse compromisso é usar o método ZIP de download, que pode aceitar qualquer referência, por exemplo: https://github.com/cirosantilli/myrepo/archive/sha.zip
É possível buscar os shas ausentes::
- Listando eventos da API com
type": "PushEvent"
. Por exemplo, o meu: https://api.github.com/users/cirosantilli/events/public (Wayback Machine) - mais convenientemente às vezes, olhando para as solicitações de tração que tentavam remover o conteúdo
- Listando eventos da API com
Existem arranhões como http://ghtorrent.org/ e https://www.githubarchive.org/ Isso reúne regularmente os dados do GitHub e os armazena em outro lugar.
Eu não consegui encontrar se eles rasparem a diferença real, e isso é improvável, porque haveria muitos dados, mas é tecnicamente possível, e a NSA e os amigos provavelmente tenham filtros para arquivar apenas coisas ligadas a pessoas ou compromissos de interesse.
Se você excluir o repositório em vez de apenas forçar pressionando, no entanto, as confirmações desaparecem mesmo da API imediatamente e dão 404, por exemplo, https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 Isso funciona mesmo se você recriar outro repositório com o mesmo nome.
Para testar isso, criei um repo: https://github.com/cirosantilli/test-dangling e fez:
git init
git remote add origin git@github.com:cirosantilli/test-dangling.git
touch a
git add .
git commit -m 0
git push
touch b
git add .
git commit -m 1
git push
touch c
git rm b
git add .
git commit --amend --no-edit
git push -f
Veja também: Como remover um compromisso pendurado do Github?
Para ficar claro: a resposta aceita está correta. Experimente primeiro. No entanto, pode ser desnecessariamente complexo para alguns casos de uso, principalmente se você encontrar erros desagradáveis, como 'Fatal: Bad Revisão-Presune-Deepy', ou realmente não se importa com a história do seu repo.
Uma alternativa seria:
- CD para o ramo base do projeto
- Remova o código / arquivo sensível
- rm -rf .git/ # remova todas as informações git do seu código
- Vá para o Github e exclua seu repositório
- Siga este guia para empurrar seu código para um novo repositório como normalmente faria -https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
É claro que isso removerá todos os ramos históricos e os problemas do seu repositório do GitHub e do seu repositório local. Se isso for inaceitável, você precisará usar uma abordagem alternativa.
Chame isso de opção nuclear.
Aqui está minha solução no Windows
Filtro de Git-Branch-Tree-filter "rm -f 'filedir/filename'" cabeça
git push -force
Certifique -se de que o caminho esteja correto, caso contrário, não funcionará
Espero que ajude
Usar Filtro do ramo:
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all
git push origin *branch_name* -f
You can use git forget-blob
.
The usage is pretty simple git forget-blob file-to-forget
. You can get more info here
It will disappear from all the commits in your history, reflog, tags and so on
I run into the same problem every now and then, and everytime I have to come back to this post and others, that's why I automated the process.
Credits to contributors from Stack Overflow that allowed me to put this together
I've had to do this a few times to-date. Note that this only works on 1 file at a time.
Get a list of all commits that modified a file. The one at the bottom will the the first commit:
git log --pretty=oneline --branches -- pathToFile
To remove the file from history use the first commit sha1 and the path to file from the previous command, and fill them into this command:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..
So, It looks something like this:
git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore
Remove cache for tracked file from git and add that file to
.gitignore
list
In my android project I had admob_keys.xml as separated xml file in app/src/main/res/values/ folder. To remove this sensitive file I used below script and worked perfectly.
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all