web-dev-qa-db-fra.com

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

J'aimerais mettre un projet Git sur GitHub, mais il contient certains fichiers contenant 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 supprime pas leur historique dans Git.

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

Existe-t-il un moyen de supprimer tout les traces d'un fichier particulier dans votre historique Git?

298
Stefan

À toutes fins pratiques, la première chose à laquelle vous devez vous inquiéter est (MODIFICATION DE VOS MOTS DE PASSE!} _ Votre question ne vous 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é des autres, vous avez un problème. Si quelqu'un a cloné ce référentiel avant de résoudre ce problème, il conservera une copie de vos mots de passe sur sa machine locale. Il est impossible de le forcer à mettre à jour votre version "corrigée". La seule chose à faire est de changer votre mot de passe pour quelque chose d'autre partout où vous l'avez utilisé.


Avec cela, voici comment y remédier. GitHub a répondu exactement à cette question en tant que FAQ :

Remarque pour les utilisateurs de Windows: utilisez des guillemets doubles (") au lieu de simples dans cette 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 envoyé ce code dans un référentiel distant tel que GitHub et que d'autres ont cloné ce référentiel distant, vous êtes maintenant dans une situation de réécriture de l'historique. Lorsque les autres utilisateurs essaient de récupérer vos dernières modifications après cela, ils reçoivent un message indiquant que les modifications ne peuvent pas être appliquées car il ne s'agit pas d'une avance rapide. 

Pour résoudre ce problème, ils devront soit supprimer leur référentiel existant et le cloner à nouveau, soit suivre les instructions sous "RECUPÉRATION À PARTIR DE LA REBASE UPSTREAM" dans la page de manuel git-rebase .


À l'avenir, si vous validez accidentellement certaines modifications avec des informations sensibles mais que vous remarquez que avant poussant vers un référentiel distant, des correctifs plus simples sont nécessaires. Si votre dernière validation est celle pour laquelle vous ajoutez les informations sensibles, vous pouvez simplement supprimer les informations sensibles, puis exécuter:

git commit -a --amend

Cela modifiera le commit précédent avec toutes les nouvelles modifications que vous avez apportées, y compris la suppression de fichiers entiers avec un git rm. Si les modifications sont plus en arrière dans l'historique mais ne sont toujours pas poussées vers un référentiel distant, vous pouvez effectuer une rebase interactive:

git rebase -i Origin/master

Cela ouvre un éditeur avec les commits que vous avez effectués depuis votre dernier ancêtre commun avec le référentiel distant. Remplacez "pick" par "edit" sur toutes les lignes représentant une validation avec des informations sensibles, puis enregistrez et quittez. Git suivra les modifications et vous laissera à un endroit où vous pourrez:

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

Pour chaque changement avec des informations sensibles. Finalement, vous allez revenir sur votre branche et vous pouvez pousser en toute sécurité les nouvelles modifications.

381
natacado

Changer vos mots de passe est une bonne idée, mais pour le processus de suppression des mots de passe de l'historique de votre référentiel, je recommande le BFG Repo-Cleaner , une alternative plus rapide et plus simple à git-filter-branch explicitement conçue pour supprimer les données privées des référentiels Git.

Créez un fichier private.txt répertoriant les mots de passe, etc. que vous souhaitez supprimer (une entrée par ligne), puis exécutez la commande suivante:

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

Tous les fichiers de taille inférieure à un seuil (1 Mo par défaut) dans l'historique de votre référentiel seront analysés et toute chaîne correspondante (ne figurant pas dans votre dernière commit) sera remplacée par la chaîne "*** REMOVED *** ". Vous pouvez ensuite utiliser git gc pour effacer les données mortes:

$ git gc --Prune=now --aggressive

Le BFG est généralement 10 à 50 fois plus rapide que l'exécution de git-filter-branch et les options sont simplifiées et personnalisées autour de ces deux cas d'utilisation courants:

  • Supprimer Crazy Big Files
  • Suppression de mots de passe, informations d'identification et autres données privées

_ {Divulgation complète: je suis l'auteur du BFG Repo-Cleaner.} _

71
Roberto Tyley

Je recommande ce script de David Underhill, a fonctionné à merveille pour moi. 

Il ajoute ces commandes en plus de la branche-filtre de natacado pour nettoyer le gâchis qu'il laisse derrière lui:

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

Texte complet (tout crédit à 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 fonctionner mieux si elles sont modifiées comme suit:

git reflog expire --expire=now --all && \
git gc --aggressive --Prune=now
17
Jason Goemaat

Si vous avez déjà poussé sur GitHub, les données sont compromises même si vous forcez Push it away une seconde plus tard parce que:

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

git init
git remote add Origin [email protected]: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 supprimez le référentiel, les validations disparaissent même immédiatement de l’API et donnent 404, par exemple. https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 Ceci fonctionne même si vous recréez un autre référentiel portant le même nom.

Donc, mon action recommandée est:

  • changer vos identifiants

  • si cela ne suffit pas (par exemple, des photos nues):

    • supprimer le référentiel
    • contactez le support

Pour être clair: la réponse acceptée est correcte. Essayez-le d'abord. Toutefois, cela peut s'avérer inutilement complexe pour certains cas d'utilisation, en particulier si vous rencontrez des erreurs odieuses telles que "fatal: bad revision" ou si vous ne vous souciez pas de l'historique de votre repo.

Une alternative serait:

  1. cd à la branche de base du projet 
  2. Supprimer le code/fichier sensible
  3. rm -rf .git/# Supprimer toutes les informations sur git de votre code 
  4. Allez sur github et supprimez votre dépôt
  5. Suivez ce guide pour Transférer votre code dans un nouveau référentiel comme vous le feriez normalement - https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command -ligne/

Ceci supprimera bien sûr toutes les branches d’historique de commit et les problèmes de votre référentiel github et de votre référentiel git local. Si cela est inacceptable, vous devrez utiliser une autre approche.

Appelez cela l'option nucléaire.

8
lostphilosopher

Voici ma solution sous windows

git filter-branch --tree-filter "rm -f 'filé/nom_fichier'" HEAD

git Push --force

assurez-vous que le chemin est correct sinon cela ne fonctionnera pas

J'espère que ça aide

6
vertigo71

Utilisez filter-branch :

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

Vous pouvez utiliser git forget-blob.

L'utilisation est assez simple git forget-blob file-to-forget. Vous pouvez obtenir plus d'informations 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 de votre historique, de vos remarques, de vos tags, etc.

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

Crédits aux contributeurs de Stack Overflow qui m'ont permis de mettre cela ensemble

4
nachoparker

J'ai eu à le faire plusieurs fois à ce jour. Notez que cela ne fonctionne que sur 1 fichier à la fois.

  1. Obtenez une liste de tous les commits qui ont modifié un fichier. Celui du bas sera le premier commis:

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

  2. Pour supprimer le fichier de l'historique, utilisez le premier commit sha1 et le chemin d'accès au fichier de la commande précédente, et entrez-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
b01

Alors, ça ressemble à quelque chose comme ça:

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

Supprimer le cache du fichier suivi de git et l'ajouter à la liste .gitignore

2
przbadu

Dans mon projet Android, j'avais le fichier admob_keys.xml en tant que fichier xml séparé dans le dossier app/src/main/res/values ​​/ . Pour supprimer ce fichier sensible, j'ai utilisé le script ci-dessous et a parfaitement fonctionné.

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
0
Ercan Duman