Comment supprimer une révision spécifique dans l’historique git ?

StackOverflow https://stackoverflow.com/questions/37219

  •  09-06-2019
  •  | 
  •  

Question

Supposons que votre historique Git ressemble à ceci :

1 2 3 4 5

1 à 5 sont des révisions distinctes.Vous devez supprimer 3 tout en conservant 1, 2, 4 et 5.Comment cela peut-il être fait?

Existe-t-il une méthode efficace lorsqu’il y a des centaines de révisions après celle à supprimer ?

Était-ce utile?

La solution

Pour combiner les révisions 3 et 4 en une seule révision, vous pouvez utiliser git rebase.Si vous souhaitez supprimer les modifications de la révision 3, vous devez utiliser la commande d'édition en mode rebase interactif.Si vous souhaitez combiner les modifications en une seule révision, utilisez squash.

J'ai utilisé avec succès cette technique de squash, mais je n'ai jamais eu besoin de supprimer une révision auparavant.La documentation git-rebase sous « Splitting commits » devrait, espérons-le, vous donner suffisamment d'idées pour le comprendre.(Ou quelqu'un d'autre pourrait le savoir).

Du documentation git:

Commencez-le avec le commit le plus ancien que vous souhaitez conserver tel quel :

git rebase -i <after-this-commit>

Un éditeur sera lancé avec tous les commits de votre branche actuelle (en ignorant les commits de fusion), qui surviennent après le commit donné.Vous pouvez réorganiser les commits de cette liste à votre guise et vous pouvez les supprimer.La liste ressemble plus ou moins à ceci :

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Les descriptions en ligne sont uniquement pour votre plaisir ;git-rebase ne les examinera pas mais les noms de commit ("deadbee" et "fa1afe1" dans cet exemple), donc ne supprimez ni ne modifiez les noms.

En remplaçant la commande "pick" par la commande "edit", vous pouvez dire à git-rebase de s'arrêter après avoir appliqué ce commit, afin que vous puissiez modifier les fichiers et/ou le message de commit, modifier le commit et continuer le rebasage.

Si vous souhaitez regrouper deux commits ou plus en un seul, remplacez la commande « pick » par « squash » pour le deuxième commit et les suivants.Si les commits avaient des auteurs différents, il attribuera le commit écrasé à l'auteur du premier commit.

Autres conseils

Voici un moyen de supprimer de manière non interactive un élément spécifique <commit-id>, ne connaissant que le <commit-id> vous souhaitez supprimer :

git rebase --onto <commit-id>^ <commit-id> HEAD

Par ce commentaire (et j'ai vérifié que c'était vrai), la réponse de rado est très proche mais laisse git dans un état de tête détaché.Supprimez plutôt HEAD et utilisez-le pour supprimer <commit-id> depuis la succursale où vous vous trouvez :

git rebase --onto <commit-id>^ <commit-id>

Comme indiqué précédemment git-rebase(1) est votre ami.En supposant que les commits sont dans votre master branche, vous feriez :

git rebase --onto master~3 master~2 master

Avant:

1---2---3---4---5  master

Après:

1---2---4'---5' master

Depuis git-rebase(1) :

Une gamme de validations pourrait également être supprimée avec Rebase.Si nous avons la situation suivante:

E---F---G---H---I---J  topicA

puis la commande

git rebase --onto topicA~5 topicA~3 topicA

entraînerait la suppression des commits F et G:

E---H'---I'---J'  topicA

Ceci est utile si F et G étaient défectueux d'une manière ou d'une autre, ou ne devraient pas faire partie de Topica.Notez que l'argument à --onto et le paramètre peut être n'importe quel engagement valide.

Si tout ce que vous voulez faire est de supprimer les modifications apportées dans la révision 3, vous souhaiterez peut-être utiliser git revert.

Git revert crée simplement une nouvelle révision avec des modifications qui annulent toutes les modifications apportées à la révision que vous annulez.

Cela signifie que vous conservez des informations à la fois sur la validation indésirable et sur la validation qui supprime ces modifications.

C'est probablement beaucoup plus convivial s'il est possible que quelqu'un ait extrait de votre référentiel entre-temps, puisque le retour n'est fondamentalement qu'un commit standard.

Jusqu'à présent, toutes les réponses ne répondent pas au problème suivant :

Y a-t-il une méthode efficace lorsqu'il existe des centaines de révisions après la suppression de celle à supprimer?

Les étapes suivent, mais à titre de référence, supposons l'historique suivant :

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C:commit juste après le commit à supprimer (propre)

R.:Le commit à supprimer

B:commit juste avant le commit à supprimer (base)

En raison de la contrainte des « centaines de révisions », je suppose les conditions préalables suivantes :

  1. il y a un engagement embarrassant dont vous souhaiteriez qu'il n'existe jamais
  2. il n'y a ZÉRO de commits ultérieurs qui dépendent en fait de ce commit embarrassant (zéro conflit lors du retour)
  3. vous ne vous souciez pas d'être répertorié comme le « Committer » parmi les centaines de commits intermédiaires (« Auteur » sera conservé)
  4. vous n'avez jamais partagé le référentiel
    • ou vous avez en fait suffisamment d'influence sur toutes les personnes qui ont déjà cloné l'histoire avec cet engagement pour les convaincre d'utiliser votre nouvelle histoire
    • et toi je m'en fiche à propos réécrire l'histoire

Il s’agit d’un ensemble de contraintes assez restrictif, mais il existe une réponse intéressante qui fonctionne réellement dans ce cas particulier.

Voici les étapes :

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

S’il n’y a vraiment aucun conflit, alors cela ne devrait pas être interrompu.S'il y a des conflits, vous pouvez les résoudre et rebase --continue ou décider de vivre avec l'embarras et rebase --abort.

Maintenant tu devrais être dessus master qui n'a plus d'engagement R. dedans.Le save la branche pointe vers l'endroit où vous étiez auparavant, au cas où vous souhaiteriez vous réconcilier.

La manière dont vous souhaitez organiser le transfert de tous les autres vers votre nouvelle histoire dépend de vous.Vous devrez connaître stash, reset --hard, et cherry-pick.Et vous pouvez supprimer le base, remove-me, et save branches

Voici donc le scénario auquel j'ai été confronté et comment je l'ai résolu.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

ici R est le commit que je devais supprimer, et I est un seul commit qui vient après R

J'ai fait un commit de retour et je les ai écrasés ensemble

git revert [commit id of R]
git rebase -i HEAD~3

Pendant le rebase interactif, écrasez les 2 derniers commits.

J'ai également atterri dans une situation similaire.Utilisez le rebase interactif à l'aide de la commande ci-dessous et lors de la sélection, supprimez le 3ème commit.

git rebase -i remote/branch

Les réponses de rado et kareem ne font rien pour moi (seul le message "La branche actuelle est à jour." apparaît).Cela se produit peut-être parce que le symbole « ^ » ne fonctionne pas dans la console Windows.Cependant, selon ce commentaire, remplacer '^' par '~1' résout le problème.

git rebase --onto <commit-id>^ <commit-id>

Pour supprimer l'ancien historique des commits du dépôt git :

Exécutez d'abord sous cmd

rm -rf .git

-- recréer le dépôt à partir du courant

git init                                                                           
git add .                                                  
git commit -m "first commit"

-- pousser vers les dépôts distants github

git remote add origin git@github.com<your git mail>   
git push -u --force origin master
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top