J'ai besoin de faire apparaître et de supprimer un commit «intermédiaire» dans ma branche principale. Comment puis-je le faire?

94

Par exemple, dans la branche principale suivante, je dois supprimer uniquement le commit af5c7bf16e6f04321f966b4231371b21475bc4da, qui est le deuxième en raison du rebase précédent:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <[email protected]>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <[email protected]>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

J'ai besoin de rester

  • le premier commit 60b413512e616997c8b929012cf9ca56bf5c9113,
  • le troisième commit e6523efada4d75084e81971c4dc2aec621d45530 et
  • le dernier commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"jeter" juste le deuxième commit af5c7bf16e6f04321f966b4231371b21475bc4da

Comment puis je faire ça? Merci d'avance Luca

Luca G. Soave
la source

Réponses:

98

Rebase ou revert sont les options. Rebase supprimera en fait le commit de l'historique donc il semblera que ce deuxième commit n'a jamais existé. Ce sera un problème si vous avez poussé la branche principale vers d'autres dépôts. Si vous essayez de pousser après un rebase dans ce cas, git vous donnera une erreur de rejet des fusions sans avance rapide .

Revert est la bonne solution lorsque la branche a été partagée avec d'autres dépôts. git revert af5c7bf16fera un nouveau commit qui annule simplement les changements introduits par af5c7bf16. De cette façon, l'historique n'est pas réécrit, vous conservez un enregistrement clair de l'erreur et les autres dépôts accepteront la poussée.

Voici un bon moyen d'effacer: git rebase -i <commit>^ cela vous amène au commit juste avant celui que vous souhaitez supprimer. L'éditeur interactif vous montrera une liste de tous les commits jusqu'à ce point. Vous pouvez sélectionner, écraser, etc. Dans ce cas, supprimez la ligne du commit que vous souhaitez effacer et enregistrez le fichier. Rebase terminera son travail.

JCoton
la source
2
Au cas où je choisirais Rebase, quel est le bon commit pour rebase? Je dois laisser tomber juste la seconde ...
Luca G. Soave
@ BBJ3 Voir la réponse de mipadi.
Prajwal Dhatwalia
32

Si le rebase est une option, vous pouvez le rebaser et simplement le déposer:

$ git rebase -i 414ceffc^

Si le rebase n'est pas une option, vous pouvez simplement l'annuler:

$ git revert af5c7bf16
mipadi
la source
si je suis pour "git rebase 414ceffc" qui est le quatrième commit le plus ancien, est-ce que je perdrai aussi le troisième e6523 et le premier 60b41?
Luca G.Soave
3
@Luca G. Soave: Vous ne «perdez» un commit que si vous dites spécifiquement git rebasede le laisser tomber (en s'exécutant rebaseen mode interactif et en supprimant son entrée).
mipadi
Merci mipadi, je donne mon vote à JCotton essentiellement pour l'explication détaillée même si vous deux, avez dit la même chose ... merci encore.
Luca G.Soave
29

Malgré tout le crédit que les réponses originales ont reçu ici, je ne les ai pas trouvées pour répondre de manière satisfaisante à la question. Si vous vous trouvez dans une situation où vous devez supprimer un commit ou une collection de commits du milieu de l'historique, voici ce que je suggère:

  • Créez une nouvelle branche hors de la tête de celle contenant tous les commits et basculez-y.
  • Rétablissez la nouvelle branche au point à partir duquel vous souhaitez démarrer une nouvelle base.
  • Ensuite, (voici le point clé) choisissez les commits suivants que vous voulez réellement appliquer après cela de la branche d'origine à la nouvelle, et ignorez les commits que vous ne voulez plus (c'est-à-dire ceux que vous supprimez).
  • Si vous le souhaitez, renommez la branche d'origine en quelque chose indiquant qu'il s'agit de l'ancien code, puis renommez votre nouvelle branche comme la branche d'origine a été appelée.
  • Enfin, transmettez vos modifications à votre dépôt distant (si vous en utilisez un). Vous devrez probablement utiliser une "poussée forcée". Si vos collaborateurs rencontrent des problèmes pour extraire les révisions, il peut être plus simple pour eux de simplement cloner à nouveau le dépôt à partir de la source distante. D'une manière ou d'une autre, vous voudrez probablement leur parler si vous arrachez de toute façon des commits au milieu de votre histoire!

Voici des informations sur Cherry Picking: Que signifie choisir un commit avec git?

En voici quelques-uns sur le faire avec Tortoise Git (comme je viens de le faire). Il est certainement plus facile d'utiliser un utilitaire d'interface graphique pour ce genre d'opérations! Cueillette de cerises avec TortoiseGit

BuvinJ
la source
6
Cela aurait dû être la meilleure réponse!
MadOgre
Belle façon d'utiliser cherry pick, cette solution est encore meilleure lorsque vous voulez "sauter" plus d'un commit.
Johnny Willer
Ne répond pas vraiment à la question initiale. Bien que la solution suggérée fonctionne, elle prend beaucoup plus de temps / gêne et l'OMI n'apporte aucun avantage. Si la branche a déjà été poussée (et utilisée dans la nature), la stratégie de retour est probablement la réponse. Sinon, rebase interactif et supprimer le commit incriminé est ce que j'utiliserais. S'il a été poussé mais que nous savons qu'il n'est utilisé par personne, vous pouvez toujours vous en tirer avec un rebase suivi d'une poussée forcée.
raduw