Comment corriger la validation de la mauvaise branche Git?

621

Je viens de m'engager parfaitement dans la mauvaise branche. Comment annuler la dernière validation de ma branche principale, puis prendre ces mêmes modifications et les insérer dans ma branche de mise à niveau?

mikewilliamson
la source

Réponses:

975

Si vous n'avez pas encore poussé vos modifications, vous pouvez également effectuer une réinitialisation logicielle:

git reset --soft HEAD^

Cela annulera la validation, mais remettra les modifications validées dans votre index. En supposant que les branches sont relativement à jour les unes par rapport aux autres, git vous permettra de passer à la caisse dans l'autre branche, après quoi vous pourrez simplement valider:

git checkout branch
git commit

L'inconvénient est que vous devez ressaisir votre message de validation.

Blair Holloway
la source
10
notez que la réinitialisation logicielle laisse vos modifications par étapes et prêtes à être validées. m'a rendu un peu confus lorsque mon IDE n'a pas montré que les fichiers reviennent à l'état modifié après une réinitialisation logicielle.
mtjhax
9
solution parfaite, a en fait eu quelques commits, tout comme HEAD ^^ et bam all is gravy
pablo
8
Merci. Cela m'a sauvé deux fois. Si les branches sont quelque peu différentes, après la réinitialisation et avant le paiement, vous devrez peut-être cacher vos modifications avant de pouvoir retirer une autre branche. Réappliquez la cachette après le paiement
Kirby
17
Utilisateurs de zsh: vous pourriez avoir besoin d'échapper au ^ comme ceci:git reset --soft HEAD\^
Stephen Fuhry
54
Si vous obtenez un Plus? dans votre ligne de commande Windows, utilisez des guillemets pour entourer HEAD ^ comme ceci: git reset --soft "HEAD ^"
Nate Cook
142

4 ans de retard sur le sujet, mais cela pourrait être utile à quelqu'un.

Si vous avez oublié de créer une nouvelle branche avant de valider et de tout valider sur master, quel que soit le nombre de validations que vous avez effectuées, l'approche suivante est plus simple:

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

Vous avez maintenant votre branche principale égale à origin/masteret toutes les nouvelles validations sont activées my_feature. Notez qu'il my_features'agit d'une branche locale, pas distante.

fotanus
la source
Merci d'avoir répondu. Maintenant, j'utilise egit et je me demande si je peux accomplir la même chose en procédant comme suit: 1) Renommez 'master' actuel en 'my_feature'. 2) Recréez le «maître» local à partir de «origine / maître». Je ne sais pas ce que fait egit sous le capot pour ces opérations mais cela semble être une solution viable
mjj1409
pourquoi la fusion? vous pouvez créer la branche directement sur master, puis remettre masterà origin/master.
caesarsol
1
C'est la partie la plus intéressante: vous n'avez pas besoin d'un certain nombre de commit, car il origin/masterest déjà sur le commit où vous souhaitez réinitialiser! Le crédit pour l'astuce est cependant cette page: github.com/blog/…
caesarsol
4
Ce devrait être la réponse acceptée. Simple, évident, direct, fonctionne quel que soit le nombre de validations et en utilisant uniquement la fonctionnalité Git de base. J'ai fait ces étapes avec TortoiseGit. Merci! :)
Ian Grainger
1
Je pensais que c'était la meilleure réponse, mais elle a une limite. Cela n'aide que si vous avez récemment tiré de la télécommande. Et cela suppose que vous avez une télécommande pour commencer. Si vous n'avez que des branches locales "master" et votre nouveau correctif de fonctionnalité, la seule bonne réponse est une réinitialisation difficile sur master qui compte un certain nombre de validations.
pauljohn32
111

Si vous avez une copie de travail propre (non modifiée)

Pour annuler un commit (assurez-vous de noter le hachage du commit pour l'étape suivante):

git reset --hard HEAD^

Pour tirer ce commit dans une branche différente:

git checkout other-branch
git cherry-pick COMMIT-HASH

Si vous avez des modifications modifiées ou non suivies

Notez également que git reset --hardcela supprimera toutes les modifications non suivies et modifiées que vous pourriez avoir, donc si vous en avez, vous préférerez peut-être:

git reset HEAD^
git checkout .
Michael Mrozek
la source
git rev-parse BRANCH_NAMEpour obtenir le sha.
wilhelmtell
12
Si vous oubliez de noter le hachage en premier, utilisez-le git reflog show <branch>!
Cascabel
2
@Jefromi J'y ai eu peur pendant une minute.
Ian Hunter
13
Pour une sensation de sécurité supplémentaire, effectuez d'abord le choix de la cerise sur la bonne branche, puis réinitialisez la mauvaise branche.
Age Mooij
1
Aussi en cas de modifications non suivies, on peut git stashavant la réinitialisation et utiliser git stash popensuite pour les restaurer, donc pas besoin d'avoir peur de la --hardpartie
Clemens Klein-Robbenhaar
20

Si vous avez déjà poussé vos modifications, vous devrez forcer votre prochaine poussée après avoir réinitialisé la TETE.

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

Avertissement: une réinitialisation matérielle annulera toutes les modifications non validées dans votre copie de travail, tandis qu'une poussée forcée remplacera complètement l'état de la branche distante par l'état actuel de la branche locale.

Juste au cas où, sur Windows (en utilisant la ligne de commande Windows, pas Bash), c'est en fait quatre ^^^^au lieu d'un, donc c'est

git reset --hard HEAD^^^^
Igor Zevaka
la source
6
Notez que vous ne devez pas forcer à pousser sur une branche que d'autres personnes utilisent, sauf si cela est absolument nécessaire - sinon, ils ne pourront pas pousser jusqu'à ce qu'ils rebasent. Si vous êtes le seul développeur à utiliser git, cela ne pose aucun problème.
Blair Holloway,
2
Ou à moins que vous ne vous rendiez compte assez rapidement avant que quelqu'un d'autre n'ait tiré les commits erronés.
Michael Mior
Si plus d'un commit est désactivé, vous pouvez spécifier le commit dont vous avez besoin: git reset --hard COMMIT_HASH git push --force
David Cramblett
17

J'ai récemment fait la même chose, où j'ai accidentellement commis un changement de maître, alors que j'aurais dû m'engager dans une autre branche. Mais je n'ai rien poussé.

Si vous venez de vous engager dans la mauvaise branche, que vous n'avez rien changé depuis et que vous n'avez pas poussé vers le référentiel, vous pouvez effectuer les opérations suivantes:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

REMARQUE: dans l'exemple ci-dessus, je rembobinais 1 commit avec git reset HEAD ~ 1. Mais si vous vouliez rembobiner n commits, alors vous pouvez faire git reset HEAD ~ n.

De plus, si vous avez fini par vous engager dans la mauvaise branche et que vous avez également fini d'écrire du code avant de vous rendre compte que vous vous êtes engagé dans la mauvaise branche, vous pouvez utiliser git stash pour enregistrer votre travail en cours:

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

REMARQUE: J'ai utilisé ce site Web comme référence https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/

Ali Mizan
la source
Une chose similaire m'est arrivée, j'ai commis quelques changements dans le master, mais j'aurais dû le faire dans une nouvelle branche et envoyer un PR, j'ai fini par faire git checkout -b new_branchjuste à partir de là, les commits étaient intacts, juste poussés et j'ai créé un PR, didn ' Je ne dois pas recommencer.
Nishchal Gautam
11

Donc, si votre scénario est que vous vous êtes engagé mastermais que vous vouliez vous engager another-branch(qui peut ou non exister déjà) mais que vous n'avez pas encore poussé, c'est assez facile à corriger.

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

Tous vos engagements masterseront désormais activés another-branch.

Source d'amour avec: http://haacked.com/archive/2015/06/29/git-migrate/

Lorcan O'Neill
la source
semble être l'approche la plus simple! Je ne sais pas pourquoi si peu d'amour et de votes positifs
keligijus
4
Cela ne semblait pas fonctionner pour moi. another-branchexistait déjà. Dans ce cas, il a simplement annulé les engagements que j'avais faits pour maîtriser et ne les a pas mis another-branch.
Giselle Serate
6

Pour développer cette réponse, au cas où vous auriez plusieurs commits à passer, par exemple developà new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started
arsenius
la source
1
J'ai eu trois engagements à revenir, et cette question semble avoir tiré mon cul du feu. Merci!
holdenweb
3

Si vous rencontrez ce problème et que vous disposez de Visual Studio, vous pouvez effectuer les opérations suivantes:

Faites un clic droit sur votre succursale et sélectionnez View History:

entrez la description de l'image ici

Cliquez avec le bouton droit sur le commit auquel vous souhaitez revenir. Et inversez ou réinitialisez au besoin.

entrez la description de l'image ici

Trevor
la source
3

Pour plusieurs validations sur la mauvaise branche

Si pour vous, il ne s'agit que d'un seul commit, il existe de nombreuses autres solutions de réinitialisation plus faciles. Pour moi, j'avais environ 10 commits accidentellement effectués au masterlieu de, appelons-le branch_xyz, et je ne voulais pas perdre l'historique des commits .

Ce que vous pouviez faire et ce qui m'a sauvé, c'était d'utiliser cette réponse comme référence, en utilisant un processus en 4 étapes, qui est -

  1. Créer une nouvelle branche temporaire à partir de master
  2. Fusionner dans la branche initialement destinée aux commits, c.-à-d. branch_xyz
  3. Annuler valide master
  4. Supprimez la branche temporaire.

Voici les étapes ci-dessus en détail -

  1. Créer une nouvelle branche à partir du master(où j'avais accidentellement commis de nombreux changements)

    git checkout -b temp_branch_xyz
    

    Remarque: le -bdrapeau est utilisé pour créer une nouvelle branche
    Juste pour vérifier si nous avons bien fait, je ferais un rapide git branchpour m'assurer que nous sommes sur la temp_branch_xyzbranche et git logpour vérifier si nous avons bien fait les commits.

  2. Fusionnez la branche temporaire dans la branche initialement destinée aux commits, c'est-à-dire branch_xyz.
    Tout d'abord, passez à la branche d'origine, c'est-à-dire branch_xyz(vous devrez peut-être git fetchsi vous ne l'avez pas encore fait)

    git checkout branch_xyz
    

    Remarque: n'utilisez pas l' -bindicateur
    Maintenant, fusionnons la branche temporaire dans la branche que nous avons actuellement en cours de paiementbranch_xyz

    git merge temp_branch_xyz
    

    Vous devrez peut-être vous occuper de certains conflits ici, le cas échéant. Vous pouvez pousser (je voudrais) ou passer aux étapes suivantes, après une fusion réussie.

  3. Annulez les engagements accidentels d' masterutiliser cette réponse comme référence, passez d'abord àmaster

    git checkout master
    

    puis annulez-le tout le long du chemin pour correspondre à la télécommande (ou pour un commit particulier, si vous le souhaitez)

    git reset --hard origin/master
    

    Encore une fois, je ferais un git logavant et un après pour m'assurer que les changements prévus prennent effet.

  4. Effacer les preuves, c'est supprimer la branche temporaire. Pour cela, vous devez d'abord extraire la branche dans laquelle le temp a été fusionné, c'est-à-dire branch_xyz(si vous restez sur masteret exécutez la commande ci-dessous, vous pourriez obtenir un error: The branch 'temp_branch_xyz' is not fully merged), alors

    git checkout branch_xyz
    

    puis supprimez la preuve de cet incident

    git branch -d temp_branch_xyz
    

Voilà.

Mitali Cyrus
la source
1

Si la branche à laquelle vous souhaitez appliquer vos modifications existe déjà ( développement de branche , par exemple), suivez les instructions fournies par fotanus ci-dessous, puis:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

Et évidemment, vous pouvez utiliser tempbranch ou tout autre nom de branche au lieu de my_feature si vous le souhaitez.

De plus, le cas échéant, retardez la fermeture du cache (appliquez) jusqu'à ce que vous ayez fusionné dans votre branche cible.

fbicknel
la source
Je pense que la première commande (checkout develop) n'est pas nécessaire ... le rebase va juste extraire "my_feature" comme première chose.
JoelFan
Vous pouvez également laisser de côté le paramètre "my_feature" de la commande "rebase" (puisque vous avez déjà extrait "my_feature"). vous pouvez également laisser de côté le paramètre "develop" de la "fusion" (puisque vous avez déjà
vérifié
1

Pour moi, cela a été résolu en annulant le commit que j'avais poussé, puis en sélectionnant ce commit dans l'autre branche.

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

Vous pouvez utiliser git logpour trouver le hachage correct, et vous pouvez pousser ces changements quand vous le souhaitez!

arr0nax
la source