Comment annuler «git commit --amend» fait au lieu de «git commit»

1296

J'ai accidentellement modifié mon commit précédent. La validation aurait dû être distincte pour conserver l'historique des modifications que j'ai apportées à un fichier particulier.

Existe-t-il un moyen d'annuler ce dernier commit? Si je fais quelque chose comme git reset --hard HEAD^, le premier commit est également annulé.

(Je n'ai pas encore poussé vers des répertoires distants)

Jesper Rønn-Jensen
la source

Réponses:

2291

Ce que vous devez faire est de créer un nouveau commit avec les mêmes détails que le HEADcommit actuel , mais avec le parent comme la version précédente de HEAD. git reset --softdéplacera le pointeur de branche de sorte que le prochain commit se produise au-dessus d'un commit différent de celui où se trouve la tête de branche actuelle.

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}
CB Bailey
la source
33
Très cool, +1. Je l'ai même fait avec l'avant-dernier point de vue git reflogpour trouver le bon numéro, par exemple {2}.
JJD
179
Juste pour être clair, la première commande est une véritable "annulation". Il produit le HEAD, le répertoire de travail (inchangé) et l'état d'index avant git commit --amend. Le 2ème est un "refaire" dans un nouveau commit. Cela fonctionne pour tout le monde git commit, pas seulement --amend.
cdunn2001
60
Donc, si vous n'avez pas modifié avec un nouveau message de validation que vous devez récupérer, la deuxième partie peut être régulière git commit.
Matt Montag
18
Pour une raison quelconque, je recevais une erreur lors de l' exécution git reset --soft HEAD@{1}: fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions. Lorsque j'ai remplacé HEAD@{1}par le hachage de validation équivalent indiqué dans git reflog(merci JJD!), Cette réponse a fonctionné à merveille!
Tim Camber
20
@TimArnold selon votre shell, vous devrez peut-être mettre des guillemets simples ou doubles HEAD@{1}. Si je lance echo HEAD@{1}dans tcsh par exemple, la sortie est HEAD@1due au fait que les accolades ont été interprétées par tcsh. Si j'utilise des guillemets simples, les accolades sont préservées.
Kelvin
136

utilisez le ref-log :

git branch fixing-things HEAD@{1}
git reset fixing-things

vous devez alors avoir toutes vos modifications précédemment modifiées uniquement dans votre copie de travail et vous pouvez recommencer

pour voir une liste complète des types d'indices précédents git reflog

knittl
la source
7
Cela efface également l'index - toujours utile, mais va au-delà d'une simple "annulation".
cdunn2001
3
y a-t-il une différence entre HEAD@{1}et HEAD~1?
neaumusic
15
@neaumusic: oui! HEAD~1est exactement le même que HEAD^et identifie le parent du commit actuel. HEAD@{1}d'autre part, fait référence au commit auquel HEAD a fait référence avant celui-ci, c'est-à-dire qu'ils signifient des commits différents lorsque vous extrayez une branche différente ou modifiez un commit.
knittl
@knittl ah pas étonnant que je ne pensais pas que cela était possible avant, merci encore, de bonnes informations
neaumusic
9
la première étape est redondante. La simplicité git reset HEAD@{1}suffit.
dwelle
79

Trouvez vos engagements modifiés en:

git log --reflog

Remarque: vous pouvez ajouter --patchpour voir le corps des commits pour plus de clarté. Identique à git reflog.

puis réinitialisez votre HEAD à n'importe quel commit précédent au point où cela allait:

git reset SHA1 --hard

Remarque: remplacez SHA1 par votre véritable hachage de validation. Notez également que cette commande perdra toutes les modifications non validées, vous pouvez donc les cacher auparavant. Vous pouvez également utiliser à la --softplace pour conserver les dernières modifications , puis les valider.

Choisissez ensuite l'autre commit dont vous avez besoin:

git cherry-pick SHA1
kenorb
la source
26
Si vous le faites git reset SHA1 --soft, vous pouvez conserver les dernières modifications, puis les valider.
pravj
24

Vous pouvez toujours diviser un commit, à partir du manuel

  • Démarrez une rebase interactive avec git rebase -i commit ^, où commit est le commit que vous souhaitez fractionner. En fait, n'importe quelle plage de validation fera l'affaire, tant qu'elle contient cette validation.
  • Marquez le commit que vous souhaitez fractionner avec l'action "modifier".
  • Quand il s'agit de modifier ce commit, exécutez git reset HEAD ^. L'effet est que la TETE est rembobinée d'une unité, et l'indice suit. Cependant, l'arbre de travail reste le même.
  • Ajoutez maintenant les modifications à l'index que vous souhaitez avoir dans le premier commit. Vous pouvez utiliser git add (éventuellement de manière interactive) ou git-gui (ou les deux) pour ce faire.
  • Validez l'index actuel avec le message de validation approprié.
  • Répétez les deux dernières étapes jusqu'à ce que votre arbre de travail soit propre.
  • Continuez le rebase avec git rebase --continue.
Arkaitz Jimenez
la source
26
trop compliqué. git reflogest tout ce dont vous avez besoin
knittl
2
Beaucoup d'étapes oui, mais chaque étape est simple et facile à faire. Cela a fonctionné pour moi et obtient mon vote.
OzBandit
5
en outre, cette réponse vous permet de sélectionner de manière sélective les modifications que vous avez accidentellement `` modifiées '', pour apporter une valeur supplémentaire à l'approche git reset --soft HEAD @ {1} (qui a résolu mon problème BTW)
Wiebe Tijsma
2
Vous pouvez également sélectionner de manière sélective les modifications avec la méthode reflog. Faites simplement git resetau lieu de git reset --soft, puis faites git add --patch.
geekofalltrades
1
Cela réécrit toujours l'histoire et nécessite une poussée de force. Selon votre situation, cela peut ou non être un problème.
Pajn
20

Peut-être intéressant de noter que si vous êtes toujours dans votre éditeur avec le message de validation, vous pouvez supprimer le message de validation et il abandonnera la git commit --amendcommande.

Justin Schulz
la source
C'est la bonne.
atilkan
Enregistré mon mais ^^
Engineercoding
14

Peut être utilisé git reflogpour obtenir deux commit avant de modifier et après modifier.

Ensuite, utilisez git diff before_commit_id after_commit_id > d.diffpour obtenir une différence entre avant modification et après modification.

Utilisation suivante git checkout before_commit_idpour revenir à avant de valider

Et dernière utilisation git apply d.diffpour appliquer le vrai changement que vous avez fait.

Cela résout mon problème.

utzcoz
la source
11

Si vous avez poussé le commit à distance puis modifié par erreur les modifications apportées à ce commit, cela résoudra votre problème. Émettez un git logpour trouver le SHA avant le commit. (cela suppose que la télécommande est nommée origine). Émettez maintenant ces commandes en utilisant ce SHA.

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit
David Sopko
la source
3
Il s'agit d'un cas particulier de la question plus générale, mais il couvrait exactement mon besoin immédiat.
dmckee --- chaton ex-modérateur
8

Vous pouvez faire ci-dessous pour annuler votre git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

Maintenant, vos modifications sont les mêmes que précédemment. Vous avez donc terminé avec l'annulation pourgit commit —amend

Maintenant, vous pouvez le faire git push origin <your_branch_name>, pour pousser à la branche.

Pratik
la source
3

Près de 9 ans de retard, mais cette variation n'a pas été mentionnée comme accomplissant la même chose (c'est une sorte de combinaison de quelques-uns d'entre eux, similaire à la première réponse ( https://stackoverflow.com/a/1459264/4642530 ) .

Rechercher toutes les têtes détachées sur une branche

git reflog show origin/BRANCH_NAME --date=relative

Trouvez ensuite le hachage SHA1

Réinitialiser à l'ancien SHA1

git reset --hard SHA1

Poussez-le ensuite vers le haut.

git push origin BRANCH_NAME

Terminé.

Cela vous ramènera entièrement à l'ancien commit.

(Y compris la date de la tête de validation détachée remplacée précédente)

Garrettmac
la source
Oui, mais je souhaite généralement réinitialiser --softpour conserver mes modifications. Je veux juste qu'il soit engagé séparément
Juan Mendes
2
  1. Paiement vers une branche temporaire avec le dernier commit

    git branch temp HEAD@{1}

  2. Réinitialiser le dernier commit

    git reset temp

  3. Maintenant, vous aurez tous les fichiers de votre commit ainsi que le commit précédent. Vérifiez l'état de tous les fichiers.

    git status

  4. Réinitialisez vos fichiers de validation à partir de l'étape git.

    git reset myfile1.js (bientôt)

  5. Rattacher ce commit

    git commit -C HEAD@{1}

  6. Ajoutez et validez vos fichiers dans une nouvelle validation.

Priyanshu Chauhan
la source