2
votes

Git: annuler tous les commits dans la branche de fonctionnalité avant le dernier commit

J'ai une branche qui a un historique de commit défectueux en raison d'une poussée forcée dans notre branche master. Fondamentalement, j'ai les commits suivants dans cet historique de branche: A, B, C, D, E où E doit être préservé mais ABCD doit être supprimé. Ils ont été ajoutés en raison d'une fusion principale dans la branche avant que ces validations ne soient supprimées de force de l'origine principale. Comment puis-je accomplir cela?

Si A était celui à préserver, je pourrais simplement réinitialiser --hard A mais c'est dans l'autre sens ....


7 commentaires

Pouvez-vous nous en dire plus sur les commits que vous souhaitez supprimer? Les commits A à D ne sont-ils pas des validations de fusion ou sont-ils des validations de fusion?


ABCD est fusionné à partir du maître (et non plus dans le maître distant) pour cela doit être supprimé. E est mon dernier commit et où HEAD est en ce moment. Je veux juste qu'E soit dans l'histoire de la branche


Pour être clair, voulez-vous annuler les modifications introduites dans ces commits (qui laisseraient les commits dans votre référentiel), ou préférez-vous vous débarrasser complètement des commits comme s'ils ne s'étaient jamais produits?


Débarrassez-vous d'eux si c'est sûr .. :) @ LasseVågsætherKarlsen


En d'autres termes, voulez-vous que le résultat final de @ -ABCDE soit @ -E ou @ -ABCDEFG G < / code> est "le changement inverse de ABCD "?


Se débarrasser d'eux réécrira l'histoire, ce qui pourrait vous obliger à faire une autre poussée forcée, encore une fois, vous êtes sûr que c'est ce que vous voulez? Si tel est le cas, vous avez déjà obtenu deux réponses en utilisant git reset qui vous aideront avec cela.


Merci de m'avoir guidé vers une réponse @ LasseVågsætherKarlsen


3 Réponses :


3
votes
# make a backup of the current state of your branch
git branch backup your_branch

# reset to the commit prior to A
git reset --hard A^

# then re-apply E
git cherry-pick E
would be a way to do this. Rebase is another (see msanford's very detailed answer on the subject)

6 commentaires

@TimBiegeleisen Oui, il ne peut pas faire ça car il perdrait alors E. Cherry. Le ramasser semble être un bon moyen d'y parvenir. Non ?


Votre réponse serait de réécrire l'histoire à distance, et en général, ce n'est pas la chose à faire.


ABCD est fusionné à partir du maître (et non plus dans le maître distant) pour cela doit être supprimé. E est mon dernier commit et où HEAD est en ce moment. Je veux juste qu'E soit dans l'histoire de la branche


@joelgullander C'est ce que je comprends, c'est le besoin auquel j'aborde dans ma réponse.


Merci cela a fonctionné. J'ai toujours peur de faire des trucs de force alors je suis content d'avoir obtenu de l'aide ici.


@joelgullander Vous pouvez facilement récupérer presque tout dans git. Cependant, voyez la note dans ma réponse sur la force de poussée. La solution ci-dessus est de loin la plus simple!



2
votes

Vous pouvez utiliser git reset --hard A ^ pour accéder au dernier "bon" commit, puis git cherry-pick E pour appliquer le commit que vous voulez garder.

Ensuite, vous devez forcer le pousser vers la branche pour réinitialiser les choses. Assurez-vous de faire savoir à tous les autres membres de l'équipe ce qui se passe.


0 commentaires

3
votes

Option avec rebase + drop

Comme Romain l'a suggéré "rebase is another", voici une façon de le faire, en supposant que vous vouliez le résultat final de @ -ABCDE pour être @ -E , comme Lasse l'a demandé.

Je propose ceci comme un autre outil dans votre toolbelt : c'est pas la solution la plus simple à ce problème. Il vous permet cependant de supprimer les commits qui ne sont pas dans l'ordre (supprimer A, C, E et conserver B, D, par exemple):

git push -f

ce qui ouvrira votre éditeur (probablement vi ) avec un tampon qui ressemble à ceci:

pick 4231648cb4 Some previous commit
d 4bccf2ce81 A some message
d 7b4cd5ff17 B some message
d faa44efb7c C some message
d 0ce0525a79 D some message
pick f104648cc3 E some message

Oui, l'ordre des commits de haut en bas est dans l'ordre temporel inverse (l'inverse de git log ) avec le plus récent en bas. C'est pourquoi "les lignes sont exécutées de haut en bas" - du plus ancien au plus récent.

En suivant les instructions, remplacez le mot pick par d code > (ou déposer ) sur les lignes que vous souhaitez supprimer.

pick 4231648cb4 Some previous commit
pick 4bccf2ce81 A some message
pick 7b4cd5ff17 B some message
pick faa44efb7c C some message
pick 0ce0525a79 D some message
pick f104648cc3 E some message

# Rebase 76eb9131b5..ed71142fcb onto 4231648cb4 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Si vous avez commis une erreur irrémédiable, comme la suppression d'une ligne, abandonnez en quittant sans enregistrer (: q! ) et réessayez.

Si tout semble bon, enregistrez et quittez le tampon (: wq ) et continuez à rebaser jusqu'à ce que votre branche soit corrigée.

Si quelque chose de bizarre se produit après cela (comme vous avez changé un hachage de validation en un qui n'existe pas, ou le rebase s'arrête pour faire quelque chose et vous ne savez pas pourquoi) vous pouvez abandonner complètement le rebase avec git rebase --abort qui vous ramènera à votre état initial.

Si votre branche semble correcte, forcez le push. p >

git rebase -i HEAD~6

Une note importante sur la force pushing

Probablement peu connue, mais la stratégie push par défaut avant git 2 est matching , c'est-à-dire g lorsque vous git push , cela va pousser toutes vos branches locales avec les noms de branche distante correspondants, pas seulement votre branche actuelle.

Donc, quand vous git push -f cela forcera le push toutes de vos branches (ceci est arrivé à un collègue hier). Vérifiez avec git config --global push.default . Cela signifie que si vous jouiez avec une autre branche, cela pourrait aussi forcer la pousser.

Je suggérerais changer la stratégie push par défaut en simple si ce n'est pas déjà le cas. Il s'agit de la valeur par défaut de git 2.

Protection des branches

Si vous utilisez une solution git hébergée de manière centralisée comme Stash / BitBucket, Gitlab ou Github, elles offrent toutes une solution so- appelées règles de "protection des branches" pour empêcher, entre autres, les développeurs de pousser de force vers les branches.

Ajouter une règle pour empêcher le push forcé vers le master et probablement la version branches.


3 commentaires

Merci beaucoup pour la partie que je n'ai pas eu le courage (et pour les parties, les connaissances) de m'écrire!


@RomainValeri Je suis heureux de vous aider! Je prépare en fait (à donner) une session de formation git et ce genre de chose m'aide à résoudre ces problèmes. Mon objectif principal en donnant mon prochain discours est "ne vous inquiétez pas - il y a 5 façons différentes de faire presque n'importe quoi dans git, et vous pouvez faire la plupart d'entre elles avec confiance que vous pouvez annuler la plupart des erreurs"


@RomainValeri De même, confronté moi-même à ce problème, j'aurais fait ce que j'ai écrit ci-dessus, sans même envisager votre solution beaucoup plus directe. Merci pour ça!