J'ai accidentellement validé un fichier indésirable ( filename.orig
lors de la résolution d'une fusion) dans mon référentiel il y a plusieurs validations, sans que je le remarque jusqu'à présent. Je souhaite supprimer complètement le fichier de l'historique du référentiel.
Est-il possible de réécrire l'historique des modifications tel qu'il filename.orig
n'a jamais été ajouté au référentiel en premier lieu?
git
git-filter-branch
git-rewrite-history
git-rm
Grant Limberg
la source
la source
Réponses:
Veuillez ne pas utiliser cette recette si votre situation n'est pas celle décrite dans la question. Cette recette sert à corriger une fusion incorrecte et à rejouer vos bonnes validations sur une fusion fixe.
Bien
filter-branch
que vous fassiez ce que vous voulez, c'est une commande assez complexe et je choisirais probablement de le faire avecgit rebase
. C'est probablement une préférence personnelle.filter-branch
peut le faire en une seule commande, légèrement plus complexe, tandis que larebase
solution effectue les opérations logiques équivalentes une étape à la fois.Essayez la recette suivante:
(Notez que vous n'avez pas réellement besoin d'une branche temporaire, vous pouvez le faire avec un 'HEAD détaché', mais vous devez prendre note de l'ID de validation généré par l'
git commit --amend
étape à fournir à lagit rebase
commande plutôt que d'utiliser la branche temporaire Nom.)la source
git rebase -i
plus rapide et toujours aussi simple? $ git rebase -i <sh1-of-merge> Marquer la bonne comme "modifier" $ git rm somefile.orig $ git commit --amend $ git rebase --continue Cependant pour une raison quelconque, j'ai toujours ce fichier quelque part le dernier fois que je l'ai fait. Manque probablement quelque chose.git rebase -i
est très utile, surtout lorsque vous avez plusieurs opérations de rebase à effectuer, mais il est difficile de décrire avec précision lorsque vous ne pointez pas réellement sur l'épaule de quelqu'un et que vous pouvez voir ce qu'il fait avec son éditeur. J'utilise vim, mais tout le monde ne serait pas satisfait de: "ggjcesquash <Esc> jddjp: wq" et des instructions comme "Déplacer la ligne du haut après la deuxième ligne actuelle et changer le premier mot de la ligne quatre pour" éditer "maintenant enregistrer et quitter "semblent rapidement plus complexes que les étapes réelles. Vous finissez normalement avec quelques - uns--amend
et des--continue
actions, ainsi.Intro: vous avez 5 solutions disponibles
L'affiche originale indique:
Il existe de nombreuses façons de supprimer complètement l'historique d'un fichier de git:
Dans le cas de l'affiche originale, la modification du commit n'est pas vraiment une option en soi, car il a fait plusieurs commits supplémentaires par la suite, mais par souci d'exhaustivité, j'expliquerai également comment le faire, pour toute autre personne qui veut de modifier leur engagement précédent.
Notez que toutes ces solutions impliquent de modifier / réécrire l' historique / les commits d'une manière une autre, donc toute personne ayant d'anciennes copies des commits devra faire un travail supplémentaire pour resynchroniser leur historique avec le nouvel historique.
Solution 1: modification des validations
Si vous avez accidentellement apporté une modification (comme l'ajout d'un fichier) dans votre validation précédente, et que vous ne souhaitez plus que l'historique de cette modification existe, vous pouvez simplement modifier la validation précédente pour en supprimer le fichier:
Solution 2: réinitialisation matérielle (éventuellement plus une rebase)
Comme la solution n ° 1, si vous voulez simplement vous débarrasser de votre commit précédent, vous avez également la possibilité de simplement réinitialiser matériellement son parent:
Cette commande réinitialisera durablement votre branche au précédent 1 er commit parent.
Cependant , si, comme l'affiche originale, vous avez effectué plusieurs validations après la validation à laquelle vous souhaitez annuler la modification, vous pouvez toujours utiliser des réinitialisations matérielles pour la modifier, mais cela implique également l'utilisation d'une rebase. Voici les étapes que vous pouvez utiliser pour modifier un commit plus loin dans l'historique:
Solution 3: rebase non interactif
Cela fonctionnera si vous souhaitez simplement supprimer un commit de l'historique:
Solution 4: rebases interactives
Cette solution vous permettra d'accomplir les mêmes choses que les solutions n ° 2 et n ° 3, c'est-à-dire de modifier ou de supprimer les validations plus loin dans l'historique que votre validation précédente, de sorte que la solution que vous choisissez d'utiliser vous appartient en quelque sorte. Les rebases interactifs ne sont pas bien adaptés pour rebaser des centaines de validations, pour des raisons de performances, donc j'utiliserais des rebases non interactifs ou la solution de branche de filtre (voir ci-dessous) dans ce genre de situations.
Pour commencer le rebase interactif, utilisez ce qui suit:
Cela amènera git à rembobiner l'historique des validations vers le parent de la validation que vous souhaitez modifier ou supprimer. Il vous présentera ensuite une liste des validations de rembobinage dans l'ordre inverse dans l'éditeur que git est configuré pour utiliser (c'est Vim par défaut):
Le commit que vous souhaitez modifier ou supprimer sera en haut de cette liste. Pour le supprimer, supprimez simplement sa ligne dans la liste. Sinon, remplacez "choisir" par "modifier" sur la 1ère ligne, comme ceci:
Ensuite, entrez
git rebase --continue
. Si vous avez choisi de supprimer entièrement le commit, alors c'est tout ce que vous devez faire (autre que la vérification, voir l'étape finale pour cette solution). Si, d'autre part, vous vouliez modifier le commit, alors git réappliquera le commit puis suspendra le rebase.À ce stade, vous pouvez supprimer le fichier et modifier la validation, puis poursuivre la rebase:
C'est ça. Comme dernière étape, que vous ayez modifié ou supprimé complètement la validation, c'est toujours une bonne idée de vérifier qu'aucune autre modification inattendue n'a été apportée à votre branche en la différenciant avec son état avant le rebase:
Solution 5: Filtrage des branches
Enfin, cette solution est préférable si vous souhaitez effacer complètement toutes les traces de l'existence d'un fichier de l'historique, et aucune des autres solutions n'est tout à fait à la hauteur.
Cela supprimera
<file>
toutes les validations, à partir de la validation racine. Si, à la place, vous souhaitez simplement réécrire la plage de validationHEAD~5..HEAD
, vous pouvez passer cela comme argument supplémentaire àfilter-branch
, comme indiqué dans cette réponse :Encore une fois, une fois l'opération
filter-branch
terminée, il est généralement judicieux de vérifier qu'il n'y a pas d'autres modifications inattendues en différenciant votre branche de son état précédent avant l'opération de filtrage:Alternative à la branche de filtre: BFG Repo Cleaner
J'ai entendu dire que l' outil BFG Repo Cleaner s'exécute plus rapidement que
git filter-branch
, alors vous voudrez peut-être également vérifier cela en option. Il est même mentionné officiellement dans la documentation de la branche filtre comme une alternative viable:Ressources additionnelles
la source
filter-branch
un recalcul des hachages? Si une équipe travaille avec un référentiel où un gros fichier doit être filtré, comment font-ils pour que tout le monde se retrouve avec le même état du référentiel?Si vous n'avez rien engagé depuis, juste
git rm
le fichier etgit commit --amend
.Si tu as
passera par chaque modification de
merge-point
àHEAD
, supprimera filename.orig et réécrira la modification. L'utilisation--ignore-unmatch
signifie que la commande n'échouera pas si, pour une raison quelconque, filename.orig est absent d'une modification. C'est la manière recommandée dans la section Exemples de la page de manuel git-filter-branch .Remarque pour les utilisateurs de Windows: le chemin du fichier doit utiliser des barres obliques
la source
git-filter-branch
semble donner la première.filter-branch
"
pas d''
utiliser Windows et non lorsque vous utilisez Windows, ou vous obtiendrez une erreur de «mauvaise révision» formulée de manière inutile.C'est le meilleur moyen:
http://github.com/guides/completely-remove-a-file-from-all-revisions
Assurez-vous simplement de sauvegarder les copies des fichiers en premier.
ÉDITER
L'édition de Neon a malheureusement été rejetée lors de l'examen.
Voir l'article Neons ci-dessous, il pourrait contenir des informations utiles!
Par exemple, pour supprimer tous les
*.gz
fichiers accidentellement validés dans le référentiel git:Cela ne fonctionnait toujours pas pour moi? (Je suis actuellement à git version 1.7.6.1)
Je ne sais pas pourquoi, car je n'avais qu'une seule branche principale. Quoi qu'il en soit, j'ai finalement fait nettoyer mon dépôt git en poussant dans un nouveau dépôt git vide et nu, par exemple
(Oui!)
Ensuite, je le clone dans un nouveau répertoire et je déplace le dossier .git dans celui-ci. par exemple
(ouais! enfin nettoyé!)
Après avoir vérifié que tout va bien, vous pouvez supprimer les répertoires
../large_dot_git
et../tmpdir
(peut-être dans quelques semaines ou mois à partir de maintenant, juste au cas où ...)la source
--prune-empty
à la commande filter-branch.La réécriture de l'historique de Git nécessite de modifier tous les ID de validation affectés.Par conséquent, tous ceux qui travaillent sur le projet devront supprimer leurs anciennes copies du référentiel et faire un nouveau clone après avoir nettoyé l'historique. Plus il dérange de personnes, plus vous avez besoin d'une bonne raison de le faire - votre fichier superflu ne pose pas vraiment de problème, mais si seulement vous travaillez sur le projet, vous pouvez aussi bien nettoyer l'historique Git si vous le souhaitez à!
Pour le rendre aussi simple que possible, je recommanderais d'utiliser le BFG Repo-Cleaner , une alternative plus simple et plus rapide à
git-filter-branch
spécifiquement conçue pour supprimer des fichiers de l'historique Git. Une façon de vous faciliter la vie ici est qu'il gère en fait toutes les références par défaut (toutes les balises, les branches, etc.) mais il est également 10 à 50 fois plus rapide.Vous devez suivre attentivement les étapes ici: http://rtyley.github.com/bfg-repo-cleaner/#usage - mais le bit principal est juste celui-ci: téléchargez le pot BFG (nécessite Java 6 ou supérieur) et exécutez cette commande :
L'intégralité de votre historique de référentiel sera analysé et tout fichier nommé
filename.orig
(qui ne fait pas partie de votre dernier commit ) sera supprimé. C'est beaucoup plus facile que d'utilisergit-filter-branch
pour faire la même chose!Divulgation complète: je suis l'auteur du BFG Repo-Cleaner.
la source
la source
Juste pour ajouter cela à la solution de Charles Bailey, j'ai juste utilisé un git rebase -i pour supprimer les fichiers indésirables d'un commit précédent et cela a fonctionné comme un charme. Les marches:
la source
La manière la plus simple que j'ai trouvée a été suggérée par
leontalbot
(comme commentaire), qui est un article publié par Anoopjohn . Je pense que ça vaut son propre espace comme réponse:(Je l'ai converti en script bash)
Tous les crédits vont à
Annopjohn
, etleontalbot
pour le signaler.REMARQUE
Sachez que le script n'inclut pas de validations, alors assurez-vous de ne pas faire d'erreurs et d'avoir une sauvegarde en cas de problème. Cela a fonctionné pour moi, mais cela peut ne pas fonctionner dans votre situation. UTILISEZ-LE AVEC ATTENTION (suivez le lien si vous voulez savoir ce qui se passe).
la source
Certainement,
git filter-branch
c'est la voie à suivre.Malheureusement, cela ne suffira pas à supprimer complètement
filename.orig
de votre référentiel, car il peut toujours être référencé par des balises, des entrées de reflog, des télécommandes, etc.Je recommande également de supprimer toutes ces références, puis d'appeler le garbage collector. Vous pouvez utiliser le
git forget-blob
script de ce site Web pour faire tout cela en une seule étape.git forget-blob filename.orig
la source
Si c'est le dernier commit que vous voulez nettoyer, j'ai essayé avec la version 2.14.3 de git (Apple Git-98):
la source
git reflog expire --expire=now --all; git gc --prune=now
est une très mauvaise chose à faire. Sauf si vous manquez d'espace disque, laissez git garbage collecter ces commits après quelques semainesC'est pour ça que
git filter-branch
c'était prévu.la source
Vous pouvez aussi utiliser:
git reset HEAD file/path
la source