Ce que vous voulez faire est très perturbant si vous avez publié l'historique à d'autres développeurs. Voir "Récupération des rebasements en amont" dans le cadre du git rebase
documentation pour les étapes nécessaires après la réparation de votre histoire.
Vous avez au moins deux options : git filter-branch
et un rebasement interactif qui sont expliqués ci-dessous.
Utilisation de git filter-branch
J'ai rencontré un problème similaire avec des données de test binaires volumineuses provenant d'une importation Subversion et j'ai écrit sur le sujet suivant suppression des données d'un dépôt git .
Disons que votre histoire git est :
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Notez que git lola
est un alias non standard mais très utile. Avec le --name-status
nous pouvons voir les modifications de l'arbre associées à chaque commit.
Dans le commit "Careless" (dont le nom d'objet SHA1 est ce36c98) le fichier oops.iso
est le DVD-rip ajouté par accident et supprimé dans le commit suivant, cb14efd. En utilisant la technique décrite dans l'article de blog mentionné ci-dessus, la commande à exécuter est :
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
Options :
-
--prune-empty
supprime les commits qui deviennent vides ( c'est-à-dire ne modifie pas l'arbre) à la suite de l'opération de filtrage. Dans le cas typique, cette option produit un historique plus propre.
-
-d
nomme un répertoire temporaire qui n'existe pas encore, à utiliser pour construire l'historique filtré. Si vous travaillez sur une distribution Linux moderne, le fait de spécifier un fichier arbre dans /dev/shm
permettra une exécution plus rapide .
-
--index-filter
est l'événement principal et s'exécute contre l'index à chaque étape de l'historique. Vous voulez supprimer oops.iso
partout où il est trouvé, mais il n'est pas présent dans tous les commits. La commande git rm --cached -f --ignore-unmatch oops.iso
supprime le DVD-rip lorsqu'il est présent et n'échoue pas dans le cas contraire.
-
--tag-name-filter
décrit comment réécrire les noms de balises. Un filtre de cat
est l'opération d'identité. Votre référentiel, comme l'exemple ci-dessus, peut ne pas avoir de balises, mais j'ai inclus cette option pour une généralité totale.
-
--
spécifie la fin des options pour git filter-branch
-
--all
suivant --
est un raccourci pour toutes les références. Votre référentiel, comme l'exemple ci-dessus, peut n'avoir qu'une seule référence (master), mais j'ai inclus cette option pour une généralité complète.
Après un certain remue-ménage, l'histoire est maintenant :
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Notez que le nouveau commit "Careless" ajoute seulement other.html
et que le commit "Remove DVD-rip" n'est plus sur la branche master. La branche nommée refs/original/refs/heads/master
contient vos commits originaux au cas où vous auriez fait une erreur. Pour le supprimer, suivez les étapes dans "Liste de contrôle pour la réduction d'un référentiel".
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Pour une alternative plus simple, clonez le référentiel pour éliminer les éléments indésirables.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
Utilisation d'un file:///...
clone URL copie les objets plutôt que de créer uniquement des liens en dur.
Maintenant, votre histoire est :
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Les noms d'objets SHA1 pour les deux premiers commits ("Index" et "Admin page") sont restés les mêmes car l'opération de filtrage n'a pas modifié ces commits. "Careless" a perdu oops.iso
et "Page de connexion" ont un nouveau parent, donc leurs SHA1s a fait changement.
Rebasement interactif
Avec une histoire de :
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
que vous voulez supprimer oops.iso
de "Careless" comme si vous ne l'aviez jamais ajouté, et ensuite "Remove DVD-rip" est inutile pour vous. Ainsi, notre plan pour une refonte interactive est de garder "Admin page", éditer "Careless", et jeter "Remove DVD-rip".
Running $ git rebase -i 5af4522
lance un éditeur avec le contenu suivant.
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
En exécutant notre plan, nous le modifions pour
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
C'est-à-dire que nous supprimons la ligne avec "Retirer DVD-rip" et changeons l'opération sur "Careless" pour être edit
plutôt que pick
.
En quittant l'éditeur, nous nous retrouvons à une invite de commande avec le message suivant.
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Comme le message nous l'indique, nous sommes sur le commit "Careless" que nous voulons modifier, donc nous lançons deux commandes.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
La première supprime le fichier incriminé de l'index. La deuxième modifie ou amende "Careless" pour qu'il devienne l'index mis à jour, et -C HEAD
indique à git de réutiliser l'ancien message de livraison. Enfin, git rebase --continue
va de l'avant avec le reste de l'opération de rebasement.
Cela donne un historique de :
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
ce qui est ce que vous voulez.
12 votes
Cet article devrait vous aider help.github.com/removing-sensitive-data
4 votes
Connexe : Supprimer complètement un fichier de tout l'historique des commits du dépôt Git.
1 votes
Notez que si votre grand fichier se trouve dans un sous-répertoire, vous devrez spécifier le chemin relatif complet.
1 votes
Aussi lié help.github.com/fr/articles/…
0 votes
De nombreuses réponses ci-dessous vantent BFG comme étant plus simple que
git filter-branch
, mais j'ai trouvé que c'était le contraire qui était vrai.2 votes
Veuillez également jeter un œil à ma réponse qui utilise
git filter-repo
. Vous ne devriez plus utilisergit filter-branch
car c'est très lent et souvent difficile à utiliser.git filter-repo
est environ 100 fois plus rapide.0 votes
Les réponses contiennent beaucoup d'informations utiles pour les situations complexes. Pour le cas simple où vous avez ajouté le fichier puis l'avez supprimé dans le commit suivant, vous pourriez juste fusionner ces deux commits ensemble.
1 votes
Il est étonnant que tant de réponses se préoccupent de la vitesse. À quelle fréquence manipulez-vous l'historique de votre dépôt pour vous soucier de l'efficacité de cette opération ??