Supprimer les fichiers sensibles et leurs propagations de l'historique Git

je voudrais mettre un projet Git sur GitHub mais il contient certains fichiers avec des données sensibles (noms d'utilisateur et mots de passe, comme /config/deploy.rb pour capistrano).

je sais que je peux ajouter ces noms de fichiers à .gitignore , mais cela ne supprimerait pas leur histoire au sein de Git.

Je ne veux pas recommencer non plus en supprimant le /.répertoire git.

Est-il un moyen de supprimer tous les traces d'un dossier particulier dans votre histoire Git?

288
demandé sur Roberto Tyley 2009-05-16 18:49:17

10 réponses

à toutes fins pratiques, la première la chose qui devrait vous inquiéter est changer vos mots de passe! votre question ne permet pas de savoir si votre dépôt git est entièrement local ou si vous avez déjà un dépôt distant ailleurs; s'il est distant et non sécurisé par d'autres, vous avez un problème. Si quelqu'un a cloné ce dépôt avant que vous ne le répariez, ils auront une copie de vos mots de passe sur leur machine locale, et il y a aucun moyen de les forcer à mettre à jour votre "fixe" version avec elle a disparu de l'histoire. La seule chose sûre que vous pouvez faire est de changer votre mot de passe en quelque chose d'autre partout où vous l'avez utilisé.


avec cela hors du chemin, voici comment le corriger. GitHub a répondu exactement cette question comme une FAQ :

Note pour les utilisateurs de Windows : utilisez des guillemets doubles ( " ) au lieu de simples dans ce commande

git filter-branch --index-filter \
'git update-index --remove filename' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force

gardez à l'esprit qu'une fois que vous avez poussé ce code dans un dépôt distant comme GitHub et que d'autres ont cloné ce dépôt distant, vous êtes maintenant dans une situation où vous réécrivez l'histoire. Quand d'autres essayent de tirer vers le bas Vos dernières modifications après cela, ils obtiendront un message indiquant que les modifications ne peuvent pas être appliquées parce que ce n'est pas un fast-forward.

pour corriger cela, ils devront soit supprimer leur dépôt existant et le re-cloner, ou suivre les instructions sous "récupérer de REBASE amont" dans le git-rebase manpage .


dans le futur, si vous commettez accidentellement des modifications avec des informations sensibles mais que vous remarquez avant poussant vers un dépôt distant, il y a des corrections plus faciles. Si votre dernier commit est celui d'ajouter les informations sensibles, vous pouvez simplement supprimer les informations sensibles, puis exécuter:

git commit -a --amend

qui modifiera la propagation précédente avec toutes les nouvelles modifications que vous aurez apportées, y compris les suppressions de fichiers complètes effectuées avec un git rm . Si les modifications remontent plus loin dans l'histoire mais ne sont toujours pas poussées vers un dépôt distant, vous pouvez faire un rebase interactif:

git rebase -i origin/master

qui ouvre un éditeur avec les commits que vous avez faits depuis votre dernier ancêtre commun avec le dépôt distant. Changement de "ramasser" pour "modifier" sur toutes les lignes représenter un commit avec des informations sensibles, et sauvegarder et quitter. Git va parcourir les changements, et vous laisser à un endroit où vous pouvez:

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

pour chaque changement avec des informations sensibles. Finalement, vous finirez par revenir sur votre branche, et vous pourrez pousser les nouveaux changements en toute sécurité.

370
répondu natacado 2016-05-26 12:16:07

changer vos mots de passe est une bonne idée, mais pour le processus de suppression des mots de passe de l'histoire de votre repo, je recommande le BFG Repo-Cleaner , une alternative plus rapide et plus simple à git-filter-branch explicitement conçu pour supprimer des données privées de Git repos.

créer un private.txt fichier énumérant les mots de passe, etc, que vous voulez supprimer (une entrée par ligne) et puis exécuter cette commande:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

tous les fichiers sous une taille de seuil (1 Mo par défaut) dans l'historique de votre repo sera scanné, et toute chaîne correspondante (qui n'est pas dans votre dernier commit) sera remplacée par la chaîne "***REMOVED***". Vous pouvez alors utiliser git gc pour nettoyer les données mortes:

$ git gc --prune=now --aggressive

le BFG est typiquement 10-50x plus rapide que l'exécution git-filter-branch et les options sont simplifiées et adaptées autour de ces deux cas d'utilisation commune:

  • Retrait Fou De Gros Fichiers
  • suppression mots de passe, justificatifs d'identité & autres données privées

divulgation Complète: je suis l'auteur de la BFG Repo-Cleaner.

70
répondu Roberto Tyley 2014-07-11 06:41:03

je recommande ce script de David Underhill, a fonctionné comme un charme pour moi.

il ajoute ces commandes en plus de la branche-filtre de natacado pour nettoyer le désordre qu'il laisse derrière lui:

rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune

script Complet (tout le crédit de 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

les deux dernières commandes peuvent mieux fonctionner si elles sont modifiées comme suit:

git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
16
répondu Jason Goemaat 2015-01-14 03:53:50

si vous avez déjà poussé vers GitHub, les données sont compromises même si vous les repoussez une seconde plus tard parce que:

pour tester ceci, j'ai créé un repo: https://github.com/cirosantilli/test-dangling et fait:

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

si vous supprimer le dépôt cependant, commits do disparaître même de L'API immédiatement et donner 404, par exemple https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 cela fonctionne même si vous recréez un autre dépôt avec le même nom.

donc mon plan d'action recommandé est:

  • changer vos lettres de créance

  • si cela ne suffit pas (p.ex. pics nus):

    • supprimer le dépôt
    • contacter le support
10

pour être clair: la réponse acceptée est correcte. Essayez d'abord. Cependant, il peut être inutilement complexe pour certains cas d'utilisation, en particulier si vous rencontrez des erreurs odieuses telles que "fatal: bad revision --prune-empty", ou vraiment ne se soucient pas de l'histoire de votre pension.

une alternative serait:

  1. cd du projet de la base de la branche
  2. supprimer le code / fichier sensible
  3. rm-rf .Git/ # Supprimer toutes les informations de git votre code
  4. allez à github et supprimez votre dépôt
  5. suivez ce guide pour pousser votre code vers un nouveau dépôt comme vous le feriez normalement - https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line /

cela supprimera bien sûr toutes les branches de commit history, et les numéros de votre GitHub repo, et de votre git repo local. Si c'est inacceptable, vous devrez utiliser une autre approche.

appelez ça l'option nucléaire.

8
répondu lostphilosopher 2015-01-25 23:38:51

voici ma solution sous windows

git filter-branch --l'arbre-filtre "rm -f 'filedir/filename'" TÊTE

git push -- force

assurez-vous que le chemin est correct sinon ça ne marchera pas

j'espère que cela aide

6
répondu vertigo71 2016-12-02 19:19:31

utiliser branche de filtre :

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
5
répondu Shiv Krishna Jaiswal 2017-09-17 14:50:54

vous pouvez utiliser git forget-blob .

l'usage est assez simple git forget-blob file-to-forget . Vous pouvez obtenir plus d'information ici

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

il disparaîtra de tous les commits dans votre histoire, reconfigurer, tags et ainsi de suite

je rencontre le même problème de temps en temps, et à chaque fois je dois revenez à ce poste et d'autres, c'est pourquoi j'ai automatisé le processus.

crédits aux contributeurs de la pile Overflow qui m'a permis de mettre cela ensemble

4
répondu nachoparker 2017-01-23 07:41:12

j'ai dû faire ça plusieurs fois à ce jour. Notez que cela ne fonctionne que sur 1 fichier à la fois.

  1. Obtenir une liste de tous les commits que modifié un fichier. Celui du bas fera le premier commit:

    git log --pretty=oneline --branches -- pathToFile

  2. pour supprimer le fichier de l'historique, utilisez la première commande commit sha1 et le chemin de fichier de la commande précédente, et remplissez-les dans cette commande:

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..

2
répondu b01 2017-03-21 18:23:36

donc, il ressemble à quelque chose comme ceci:

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

supprimer le cache pour le fichier suivi de git et ajouter ce fichier à .gitignore liste

1
répondu przbadu 2018-02-16 04:53:08