Ce que vous voulez faire est très perturbant si vous avez publié l'historique à d'autres développeurs. Voir «Récupération à partir d'une rebase en amont» dans la git rebase
documentation pour les étapes nécessaires après la réparation de votre historique.
Vous avez au moins deux options: git filter-branch
et un rebase interactif, tous deux expliqués ci-dessous.
En utilisant git filter-branch
J'ai eu un problème similaire avec les données de test binaires volumineuses d'une importation Subversion et j'ai écrit sur la suppression des données d'un référentiel git .
Supposons que votre historique Git soit:
$ 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 qu'il git lola
s'agit d'un alias non standard mais très utile. Avec le --name-status
commutateur, nous pouvons voir les modifications d'arborescence 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é lors du prochain commit, cb14efd. En utilisant la technique décrite dans le billet de blog susmentionné, 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 validations qui deviennent vides ( c'est-à - dire , ne modifient pas l'arborescence) à 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 créer l'historique filtré. Si vous utilisez une distribution Linux moderne, la spécification d'une arborescence /dev/shm
entraînera une exécution plus rapide .
--index-filter
est l'événement principal et s'exécute par rapport à l'index à chaque étape de l'historique. Vous souhaitez supprimer oops.iso
où qu'il se trouve, mais il n'est pas présent dans toutes les validations. La commande git rm --cached -f --ignore-unmatch oops.iso
supprime le DVD-rip lorsqu'il est présent et n'échoue pas autrement.
--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é complète.
--
spécifie la fin des options git filter-branch
--all
ce qui suit --
est un raccourci pour toutes les références. Votre référentiel, comme l'exemple ci-dessus, ne peut avoir qu'une seule référence (maître), mais j'ai inclus cette option pour une généralité complète.
Après quelques barattages, 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 étiquetée refs/original/refs/heads/master
contient vos commits originaux au cas où vous auriez fait une erreur. Pour le supprimer, suivez les étapes de la «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 bits indésirables.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
L'utilisation d'une file:///...
URL de clonage copie des objets plutôt que de créer uniquement des liens physiques.
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'objet SHA1 pour les deux premières validations («Index» et «Page Admin») sont restés les mêmes car l'opération de filtrage n'a pas modifié ces validations. "Careless" a perdu oops.iso
et "Login page" a eu un nouveau parent, donc leurs SHA1 ont changé.
Rebase interactive
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
vous voulez supprimer oops.iso
de "Careless" comme si vous ne l'aviez jamais ajouté, puis "Remove DVD-rip" est inutile pour vous. Ainsi, notre plan d'entrer dans un rebase interactif est de conserver la «page Admin», de modifier «Careless» et de supprimer «Remove DVD-rip».
L'exécution $ git rebase -i 5af4522
démarre 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
# ...
Autrement dit, nous supprimons la ligne avec «Supprimer DVD-rip» et modifions l'opération sur «Careless» edit
plutôt que pick
.
Enregistrer-quitter l'éditeur nous dépose à 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 éditer, nous exécutons donc deux commandes.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
Le premier supprime le fichier incriminé de l'index. Le second modifie ou modifie «Careless» pour être l'index mis à jour et -C HEAD
demande à git de réutiliser l'ancien message de validation. Enfin, git rebase --continue
continue avec le reste de l'opération de rebase.
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
c'est ce que tu veux.