Comment restaurer un référentiel Git à un commit précédent?

7630

Comment revenir de mon état actuel à un instantané effectué sur un certain commit?

Si je le fais git log, j'obtiens la sortie suivante:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <[email protected]>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <[email protected]>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <[email protected]>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <[email protected]>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

Comment revenir à la validation à partir du 3 novembre, c'est-à-dire la validation 0d1d7fc?

Crazy Serb
la source
116
Voici un article très clair et complet sur l'annulation des choses dans git, directement depuis Github.
Nobita
3
Connexes: restauration d'un ancien commit Git dans un dépôt public . Notez que cette question ajoute une contrainte que le dépôt est public.
58
J'adore Git, mais le fait qu'il y ait 35 réponses à quelque chose qui devrait être incroyablement simple expose un énorme problème avec Git. Ou est-ce les documents?
The Muffin Man
2
Comment le langage "piège" en utilisant le mot pour revenir comme signifiant familièrement pour réinitialiser même pas adressé ici ??? 6594 votes positifs jusqu'à présent et non une modification de cette manière, pour souligner la différence? Il ne serait pas plus déroutant de faire référence à "enregistrer un fichier" ici avec l'expression "commettre" ...
RomainValeri

Réponses:

9733

Cela dépend beaucoup de ce que vous entendez par "revenir".

Passer temporairement à un autre commit

Si vous voulez y revenir temporairement, vous amuser, puis revenir là où vous êtes, il vous suffit de vérifier le commit souhaité:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

Ou si vous voulez faire des commits pendant que vous y êtes, allez-y et créez une nouvelle branche pendant que vous y êtes:

git checkout -b old-state 0d1d7fc32

Pour revenir à l'endroit où vous vous trouviez, vérifiez à nouveau la branche dans laquelle vous vous trouviez. (Si vous avez apporté des modifications, comme toujours lorsque vous changez de branche, vous devrez les traiter comme il convient. Vous pouvez réinitialiser pour les jeter; vous pouvez cacher, retirer, cacher la pop pour les emporter avec vous; vous pouvez vous engager à une succursale là-bas si vous voulez une succursale là-bas.)

Supprimer définitivement les validations non publiées

Si, d'autre part, vous voulez vraiment vous débarrasser de tout ce que vous avez fait depuis, il y a deux possibilités. Premièrement, si vous n'avez publié aucun de ces commits, réinitialisez simplement:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

Si vous vous trompez, vous avez déjà supprimé vos modifications locales, mais vous pouvez au moins revenir à votre position précédente en réinitialisant à nouveau.

Annuler les validations publiées avec de nouvelles validations

D'un autre côté, si vous avez publié le travail, vous ne voudrez probablement pas réinitialiser la branche, car cela réécrit effectivement l'historique. Dans ce cas, vous pouvez en effet annuler les commits. Avec Git, revert a une signification très spécifique: créer un commit avec le patch inverse pour l'annuler. De cette façon, vous ne réécrivez aucun historique.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

La git-revertpage de manuel couvre en fait une grande partie de cela dans sa description. Un autre lien utile est cette section git-scm.com traitant de git-revert .

Si vous décidez que vous ne voulez pas revenir après tout, vous pouvez annuler le retour (comme décrit ici) ou réinitialiser à avant le retour (voir la section précédente).

Vous pouvez également trouver cette réponse utile dans ce cas:
Comment déplacer HEAD vers un emplacement précédent? (Tête détachée)

Cascabel
la source
118
Le commentaire de @ Rod sur git revert HEAD~3le meilleur wat pour revenir en arrière 3est une convention importante.
New Alexandria
20
Pourriez-vous écrire le nombre entier? comme:git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Spoeken
16
@MathiasMadsenStav Oui, vous pouvez bien sûr spécifier des commits par le SHA1 complet. J'ai utilisé des hachages abrégés pour rendre la réponse plus lisible, et vous avez également tendance à les utiliser si vous tapez. Si vous copiez et collez, utilisez absolument le hachage complet. Voir Spécification des révisions dans man git rev-parse pour une description complète de la façon dont vous pouvez nommer les validations.
Cascabel
59
Vous pouvez utiliser git revert --no-commit hash1 hash2 ...et après cela juste valider chaque retour en un seul commitgit commit -m "Message"
Mirko Akov
6
Que signifie «publier» dans ce contexte?
Howiecamp
1852

Beaucoup de réponses compliquées et dangereuses ici, mais c'est en fait facile:

git revert --no-commit 0766c053..HEAD
git commit

Cela ramènera tout du HEAD au hachage de validation, ce qui signifie qu'il recréera cet état de validation dans l'arborescence de travail comme si chaque validation depuis avait été parcourue. Vous pouvez ensuite valider l'arborescence actuelle, et cela créera une toute nouvelle validation essentiellement équivalente à la validation à laquelle vous "êtes revenu".

(L' --no-commitindicateur permet à git d'annuler toutes les validations à la fois, sinon vous serez invité à fournir un message pour chaque validation de la plage, jonçant votre historique de nouvelles validations inutiles.)

Il s'agit d'un moyen sûr et facile de revenir à un état précédent . Aucun historique n'est détruit, il peut donc être utilisé pour des commits qui ont déjà été rendus publics.

Yarin
la source
23
Si vous voulez vraiment avoir des validations individuelles (au lieu de tout annuler avec un gros commit), vous pouvez passer à la --no-editplace de --no-commit, de sorte que vous n'ayez pas à modifier un message de validation pour chaque réversion.
88
Si l'une des validations entre 0766c053..HEAD est une fusion, une erreur apparaîtra (à faire sans -m spécifié). Cela peut aider ceux qui rencontrent cela: stackoverflow.com/questions/5970889/…
timhc22
7
Pour voir les différences avant de valider, utilisez git diff --cached.
John Erck
21
$ git revert --no-commit 53742ae..HEADretoursfatal: empty commit set passed
Alex G
10
@AlexG c'est parce que vous devez entrer le hachage avant celui auquel vous souhaitez revenir. Dans mon cas, les hachages étaient comme: 81bcc9e HEAD{0}; e475924 HEAD{1}, ...(à partir de git reflog), et je voulais annuler ce que j'avais fait 81bcc9e, alors je devais le fairegit revert e475924..HEAD
EpicPandaForce
1611

Rogue Coder?

Vous travaillez seul et vous voulez juste que ça marche? Suivez ces instructions ci-dessous, ils ont fonctionné de manière fiable pour moi et beaucoup d'autres depuis des années.

Travailler avec les autres? Git est compliqué. Lisez les commentaires sous cette réponse avant de faire quelque chose de téméraire.

Rétablissement de la copie de travail à la validation la plus récente

Pour revenir à une validation précédente, en ignorant toutes les modifications:

git reset --hard HEAD

où HEAD est le dernier commit de votre branche actuelle

Rétablissement de la copie de travail vers un commit plus ancien

Pour revenir à un commit plus ancien que le commit le plus récent:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

Les crédits vont à une question de débordement de pile similaire, revenir à un commit par un hachage SHA dans Git? .

boulder_ruby
la source
33
Je l'ai fait, mais je n'ai pas pu valider et pousser vers le référentiel distant. Je veux qu'un commit plus ancien spécifique devienne HEAD ...
Lennon
7
Cela signifie que vous avez déjà inséré les commits que vous souhaitez annuler. Cela peut créer beaucoup de problèmes pour les personnes qui ont extrait votre code et y ont travaillé. Puisqu'ils ne peuvent pas appliquer votre commit en douceur sur le leur. Dans ce cas, mieux vaut faire un git revert. Si vous êtes le seul à utiliser le repo. Faites un git push -f (Mais réfléchissez bien avant de faire ça)
vinothkr
6
Je viens aussi tiens à souligner que, à défaut pour la solution de réinitialisation logicielle, au lieu de faire une remise à zéro mixte première et une réinitialisation matérielle dernier, vous pouvez réellement faire le redémarrage à froid d' abord, comme suit: git reset --hard 56e05fc; git reset --soft HEAD@{1}; git commit.
5
@nuton linus lui-même, le créateur de git, l'a critiqué pour être trop compliqué. Il est sur le disque disant qu'il était "choqué" git est devenu si populaire compte tenu de sa complexité
boulder_ruby
5
@boulder_ruby Je pense que vous vouliez dire que Linus Torvalds était le créateur de git. Mais je pense que Linus Pauling conviendrait probablement que git est compliqué.
Suncat2000
215

La meilleure option pour moi et probablement pour d'autres est l'option de réinitialisation de Git:

git reset --hard <commidId> && git clean -f

Cela a été la meilleure option pour moi! C'est simple, rapide et efficace!


** Remarque: ** Comme mentionné dans les commentaires, ne faites pas cela si vous partagez votre branche avec d'autres personnes qui ont des copies des anciens commits

Toujours d'après les commentaires, si vous vouliez une méthode moins «balleuse», vous pourriez utiliser

git clean -i
Pogrindis
la source
37
Avertissement obligatoire: ne faites pas cela si vous partagez votre branche avec d'autres personnes qui ont des copies des anciens commits, car l'utilisation d'une réinitialisation matérielle comme celle-ci les obligera à resynchroniser leur travail avec la branche nouvellement réinitialisée. Pour une solution qui explique en détail comment annuler en toute sécurité des validations sans perdre de travail avec une réinitialisation matérielle, consultez cette réponse .
7
J'appuie l'avertissement de @ Cupcake ... soyez très conscient des conséquences. Notez cependant que si votre besoin est vraiment de faire disparaître à jamais ces commits de l'histoire, cette méthode reset + clean le fera, et vous aurez besoin de forcer à pousser vos branches modifiées vers toutes les télécommandes.
ashnazg
5
git clean -f DANGER DANGER
Tisch
2
Cela définit la tête de ma copie locale sur le commit souhaité. Mais alors je ne peux pas pousser de changements car il est derrière la télécommande. Et si je tire de la télécommande, elle se retrouve là où elle était au dernier commit sur la branche distante. Comment puis-je effacer complètement (de partout) plusieurs commits sur ma copie locale qui ont été poussés?
Ade
2
@Ade .. Vous pouvez utiliser le git push -fdrapeau .. Mais attention, il remplacera la télécommande .. Assurez-vous de savoir ce que vous voulez faire ...
Pogrindis
176

Avant de répondre, ajoutons un peu de contexte, expliquant ce que HEADc'est.

First of all what is HEAD?

HEADest simplement une référence au commit actuel (le plus récent) sur la branche courante. Il ne peut y en avoir qu'un seul HEADà un moment donné (hors git worktree).

Le contenu de HEAD est stocké à l'intérieur .git/HEADet contient les 40 octets SHA-1 de la validation en cours.


detached HEAD

Si vous n'êtes pas sur le dernier commit - ce qui signifie que HEAD pointe vers un commit précédent dans l'historique, il est appelé detached HEAD.

Entrez la description de l'image ici

Sur la ligne de commande, cela ressemblera à ceci - SHA-1 au lieu du nom de la branche car le HEADne pointe pas vers la pointe de la branche actuelle:

Entrez la description de l'image ici


Quelques options sur la façon de récupérer à partir d'une tête détachée:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Cela va extraire une nouvelle branche pointant vers le commit souhaité. Cette commande extrait un commit donné.

À ce stade, vous pouvez créer une branche et commencer à travailler à partir de ce point:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Vous pouvez toujours utiliser le reflog . git reflogaffichera tout changement qui a mis à jour le HEADet vérifier l'entrée de reflog souhaitée mettra le HEADdos à ce commit.

Chaque fois que le HEAD est modifié, il y aura une nouvelle entrée dans le reflog

git reflog
git checkout HEAD@{...}

Cela vous ramènera à votre engagement souhaité

Entrez la description de l'image ici


git reset HEAD --hard <commit_id>

"Déplacer" votre tête vers le commit souhaité.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Remarque: ( Depuis Git 2.7 ), vous pouvez également utiliser legit rebase --no-autostash .

Ce schéma illustre quelle commande fait quoi. Comme vous pouvez le voir, reset && checkoutmodifiez le HEAD.

Entrez la description de l'image ici

CodeWizard
la source
6
Excellent indice git reflog, c'est exactement ce dont j'avais besoin
smac89
4
Aie! Tout cela semble terriblement compliqué ... n'y a-t-il pas une simple commande qui vous fait juste reculer d'un pas? Comme passer de la version 1.1 de votre projet à la version 1.0? Je m'attendais à quelque chose comme: git stepback_one_commit ou quelque chose ....
Kokodoko
il y a: git reset HEAD^--hard`
CodeWizard
3
@Kokodoko Oui, c'est horriblement compliqué ... et un parfait exemple du peu de considération que les experts ont pour les gens qui commencent tout juste. Veuillez vous référer à ma réponse ici, ainsi qu'au livre que je recommande. Git n'est PAS quelque chose que vous pouvez simplement saisir intuitivement. Et je peux être absolument certain que CodeWizard ne l'a pas fait.
mike rodent
145

Si vous souhaitez "annuler l'engagement", effacer le dernier message de validation et remettre les fichiers modifiés en attente, vous utiliserez la commande:

git reset --soft HEAD~1
  • --softindique que les fichiers non validés doivent être conservés en tant que fichiers de travail par opposition à ceux --hardqui les élimineraient.
  • HEAD~1est le dernier commit. Si vous souhaitez annuler 3 commits, vous pouvez les utiliser HEAD~3. Si vous souhaitez revenir à un numéro de révision spécifique, vous pouvez également le faire à l'aide de son hachage SHA.

Il s'agit d'une commande extrêmement utile dans les situations où vous avez commis la mauvaise chose et que vous souhaitez annuler ce dernier commit.

Source: http://nakkaya.com/2009/09/24/git-delete-last-commit/

Stephen Ostermiller
la source
3
C'est doux et doux: sans risque si vous n'avez pas poussé votre travail
nilsM
124

Vous pouvez le faire à l'aide des deux commandes suivantes:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Cela supprimera votre précédent commit Git.

Si vous souhaitez conserver vos modifications, vous pouvez également utiliser:

git reset --soft [previous Commit SHA id here]

Ensuite, il enregistrera vos modifications.

kiran boghra
la source
2
J'ai essayé une demi-douzaine de réponses dans ce post jusqu'à ce que j'arrive à celui-ci .. tous ces autres, ma configuration git ne cessait de me donner une erreur en essayant de pousser. Cette réponse a fonctionné. Merci!
Gene Bo
Un détail pour moi, c'est que j'ai perdu les diffs .. que je voulais garder pour voir ce que j'avais fait dans le commit qui ne fonctionnait pas. La prochaine fois, je voudrais simplement enregistrer ces données avant d'émettre cette commande de réinitialisation
Gene Bo
1
C'était la seule façon pour moi d'annuler une mauvaise fusion, le retour ne fonctionnait pas dans ce cas. Merci!
Dave Cole
Meilleure réponse. Merci
Imran Pollob
Meilleure réponse, merci.
user1394
114

J'ai essayé de nombreuses façons de rétablir les modifications locales dans Git, et il semble que cela fonctionne mieux si vous souhaitez simplement revenir au dernier état de validation.

git add . && git checkout master -f

Brève description:

  • Il ne créera AUCUN commit git revert fait.
  • Il ne détachera PAS votre tête comme git checkout <commithashcode> fait.
  • Il remplacera toutes vos modifications locales et SUPPRIMERA tous les fichiers ajoutés depuis le dernier commit de la branche.
  • Il ne fonctionne qu'avec les noms de branches, vous pouvez donc revenir uniquement au dernier commit de la branche.

J'ai trouvé un moyen beaucoup plus pratique et simple d'obtenir les résultats ci-dessus:

git add . && git reset --hard HEAD

où HEAD pointe vers le dernier commit de votre branche actuelle.

C'est le même code que suggéré par boulder_ruby, mais j'ai ajouté git add .avant git reset --hard HEADd'effacer tous les nouveaux fichiers créés depuis le dernier commit car c'est ce que la plupart des gens attendent, je pense, lors du retour au dernier commit.

Roman Minenok
la source
83

OK, revenir à un commit précédent dans Git est assez facile ...

Revenir en arrière sans conserver les modifications:

git reset --hard <commit>

Revenez en arrière en conservant les modifications:

git reset --soft <commit>

Explication: à l' aide de git reset, vous pouvez réinitialiser un état spécifique. Il est courant de l'utiliser avec un hachage de validation comme vous le voyez ci-dessus.

Mais comme vous voyez, la différence est d'utiliser les deux drapeaux --softet --hard, par défaut, d' git resetutiliser le --softdrapeau, mais c'est toujours une bonne pratique d'utiliser toujours le drapeau, j'explique chaque drapeau:


--doux

L'indicateur par défaut comme expliqué, pas besoin de le fournir, ne change pas l'arborescence de travail, mais il ajoute tous les fichiers modifiés prêts à être validés, vous revenez donc à l'état de validation qui modifie les fichiers sans mise en scène.


--difficile

Soyez prudent avec ce drapeau. Il réinitialise l'arborescence de travail et toutes les modifications apportées aux fichiers suivis et tout sera parti!


J'ai également créé l'image ci-dessous qui peut se produire dans une vraie vie en travaillant avec Git:

Git réinitialisé à un commit

Alireza
la source
La valeur par défaut git resetest git reset --mixednon git reset --soft. Veuillez vérifier Quelle est la différence entre git reset --mixed, --soft et --hard? et en clair, que fait «git reset»?
Fabio dit Réintégrer Monica le
70

En supposant que vous parlez de maître et sur cette branche respective (cela dit, cela pourrait être n'importe quelle branche de travail qui vous intéresse):

# Reset local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Reset remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

J'ai trouvé la réponse dans un article de blog (maintenant n'existe plus)

Notez qu'il s'agit de réinitialiser et de forcer la modification de la télécommande, de sorte que si d'autres membres de votre équipe ont déjà tiré, vous leur causerez des problèmes. Vous détruisez l'historique des changements, ce qui est une raison importante pour laquelle les gens utilisent git en premier lieu.

Mieux vaut utiliser Revert (voir les autres réponses) que Reset. Si vous êtes une équipe d'un seul homme, cela n'a probablement pas d'importance.

Markreyes
la source
6
En quoi cette réponse est-elle différente de la myriade d'autres?
Matsmath
C'est malheureux. J'ai envoyé un e-mail au blogueur - j'espère qu'il l'a toujours!
markreyes
2
La syntaxe push est absente de la plupart des autres suggestions pour résoudre ce problème. Fonctionne très bien.
jpa57
61

Supposons que vous ayez les validations suivantes dans un fichier texte nommé ~/commits-to-revert.txt(j'avais l'habitude git log --pretty=onelinede les obtenir)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

Créez un script shell Bash pour rétablir chacun d'eux:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

Cela ramène tout à l'état précédent, y compris les créations et les suppressions de fichiers et de répertoires, le validez dans votre branche et vous conservez l'historique, mais vous le faites revenir à la même structure de fichiers. Pourquoi Git n'en a pas git revert --to <hash>me dépasse.

Lance Caraccioli
la source
41
Vous pouvez faire un git revert HEAD~3pour supprimer les 3 derniers commits
Rod
25
@Rod - Non, ce n'est pas vrai. Cette commande annulera le commit qui est le troisième grand-parent de HEAD (pas les trois derniers commits).
kflorence
1
@kflorence Ok merci pour l'info. Ça git revert -n master~3..master~1marcherait? (Vu depuis kernel.org/pub/software/scm/git/docs/git-revert.html )
Rod
3
@Rod - Cela sonne bien, c'est certainement une syntaxe laide mais n'est-ce pas? J'ai toujours trouvé que je vérifiais le commit sur lequel je voulais "revenir" et que je le commettais plus intuitivement.
kflorence
7
Il y a maintenant un moyen beaucoup plus facile de le faire qu'avec un script comme celui-ci, utilisez simplement git revert --no-commit <start>..<end>, car il git revertaccepte une plage de commit dans les nouvelles (ou toutes?) Versions de Git. Notez que le début de la plage n'est pas inclus dans le retour.
58

Alternatives supplémentaires aux solutions de Jefromi

Les solutions de Jefromi sont certainement les meilleures et vous devez absolument les utiliser. Cependant, dans un souci d'exhaustivité, je voulais également montrer ces autres solutions alternatives qui peuvent également être utilisées pour annuler une validation (dans le sens où vous créez une nouvelle validation qui annule les modifications dans la validation précédente , tout comme ce qui se git revertproduit).

Pour être clair, ces alternatives ne sont pas le meilleur moyen de revenir sur les commits , les solutions de Jefromi le sont , mais je veux juste souligner que vous pouvez également utiliser ces autres méthodes pour obtenir la même chose que git revert.

Alternative 1: réinitialisations matérielles et logicielles

Ceci est une version très légèrement modifiée de la solution de Charles Bailey pour revenir à un commit par un hachage SHA dans Git? :

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

# Commit the changes
git commit -m "Revert to <commit>"

Cela fonctionne essentiellement en utilisant le fait que les réinitialisations logicielles laisseront l'état de la validation précédente dans la zone index / staging, que vous pourrez ensuite valider.

Alternative 2: supprimer l'arborescence actuelle et la remplacer par la nouvelle

Cette solution provient de la solution de svick pour extraire l' ancien commit et en faire un nouveau commit :

git rm -r .
git checkout <commit> .
git commit

De manière similaire à l'alternative # 1, cela reproduit l'état de <commit>la copie de travail actuelle. Il est nécessaire de faire d' git rmabord car git checkoutne supprimera pas les fichiers qui ont été ajoutés depuis <commit>.

utilisateur456814
la source
À propos de l'alternative 1, une question rapide: ce faisant, nous ne perdons pas entre les commits, n'est-ce pas?
Bogac
2
@Bogac - les points indiquent un chemin de fichier, dans ce cas le répertoire courant, donc on suppose que vous l'exécutez à partir de la racine de votre copie de travail.
Tom
L'avertissement est répété plusieurs fois dans la réponse, mais quelqu'un pourrait-il ajouter pourquoi ce n'est pas le meilleur moyen - par rapport à quelque chose comme la git revert HEAD~2..HEADsolution liée de @ Cascabel (@ Jefromi). Je ne vois pas le problème.
Joshua Goldberg
55

Voici un moyen beaucoup plus simple de revenir à un commit précédent (et de l'avoir dans un état non engagé, pour en faire ce que vous voulez):

git reset HEAD~1

Donc, pas besoin d'ID de validation et ainsi de suite :)

Paul Walczewski
la source
n'a pas fonctionné, un git pull après cela donne: erreur: vos modifications locales aux fichiers suivants seraient écrasées par la fusion:
malhal
1
@malhal C'est parce que vous avez eu des changements non validés. Cachez-les / réinitialisez-les et cela fonctionnera sans cette erreur.
Paul Walczewski
39

Il existe une commande (qui ne fait pas partie du noyau Git, mais qui se trouve dans le paquet git-extras ) spécifiquement pour annuler et mettre en scène les anciens commits:

git back

Selon la page de manuel , il peut également être utilisé comme tel:

# Remove the latest three commits
git back 3
Homme de l'ombre
la source
38

La meilleure façon est:

git reset --hard <commidId> && git push --force

Cela réinitialisera la branche sur la validation spécifique, puis téléchargera le serveur distant avec les mêmes validations que vous avez en local (cela éliminera complètement les commandes après cette validation spécifique)

Soyez prudent avec le --forcedrapeau supprime toutes les validations suivantes après la validation sélectionnée sans la possibilité de les récupérer.

david.t_92
la source
3
travaillé comme un charme!
Gaurav Gupta
J'ai rétrogradé car je ne vois pas comment votre réponse fournit de nouvelles informations non déjà fournies, par exemple stackoverflow.com/a/37145089/1723886 , stackoverflow.com/a/27438379/1723886 ou stackoverflow.com/a/48756719/1723886 . En fait, la plupart des validations mentionnent déjà git reset --hard, et beaucoup d'autres mentionnent l'utilisation de --force ou -f pour pousser.
Alex Telon
Il fait le travail avec une seule commande, claire et simple. Vous pouvez voter contre ma réponse si vous ne l'aimez pas.
david.t_92
1
Une autre option à envisager pour l'avenir consiste à suggérer une modification sur une réponse antérieure ou à ajouter un commentaire disant que «cela peut également être fait sur une seule ligne en utilisant &&» par exemple. De cette façon, tout le monde peut alors voir la réponse améliorée en un seul endroit.
Alex Telon
36

Après toutes les modifications, lorsque vous appuyez sur toutes ces commandes, vous devrez peut-être utiliser:

git push -f ...

Et pas seulement git push.

sivi
la source
15
Avertissement obligatoire: ne faites pas cela si vous partagez votre branche avec d'autres personnes qui ont des copies des anciens commits, car l'utilisation d'une poussée forcée comme celle-ci les obligera à resynchroniser leur travail. Pour une solution qui explique en détail comment annuler en toute sécurité les validations sans perdre de travail avec une poussée forcée, consultez cette réponse .
3
Parfois, c'est ce que vous voulez. Exemple: validé et poussé plusieurs validations vers la mauvaise branche (branche A). Après avoir choisi la cerise sur la branche B, je souhaite que ces validations soient supprimées de la branche A. Je ne voudrais pas revenir en arrière, car la restauration serait appliquée plus tard lorsque les branches A et B sont fusionnées. Faire une réinitialisation --hard <commitId> dans la branche A suivie d'une poussée forcée supprime ces commits de la branche tout en les conservant dans la branche B.Je peux m'en tirer car je sais que personne d'autre ne se développe sur la branche A.
Doug R
Merci! Je n'arrivais pas à comprendre comment obtenir la branche distante pour qu'elle corresponde à ma branche locale.
Mido
32

Vous pouvez effectuer vous-même toutes ces étapes initiales et repousser vers le référentiel Git.

  1. Tirez la dernière version de votre référentiel de Bitbucket à l'aide de la git pull --allcommande.

  2. Exécutez la commande Git log avec -n 4depuis votre terminal. Le nombre après le -ndétermine le nombre de validations dans le journal à partir de la plus récente validation de votre historique local.

    $ git log -n 4
    
  3. Réinitialisez la tête de l'historique de votre référentiel en utilisant git reset --hard HEAD~Noù N est le nombre de validations que vous souhaitez reprendre. Dans l'exemple suivant, l'en-tête serait rétrogradé d'un commit, au dernier commit de l'historique du référentiel:

  4. Poussez la modification vers le référentiel Git en utilisant git push --forcepour forcer la poussée de la modification.

Si vous souhaitez que le référentiel Git soit validé précédemment:

git pull --all
git reset --hard HEAD~1
git push --force
Nanhe Kumar
la source
30

Revenez à la validation la plus récente et ignorez toutes les modifications locales:

git reset --hard HEAD
Mohammed Irfan Tirupattur
la source
28

Sélectionnez votre validation requise et vérifiez-la par

git show HEAD
git show HEAD~1
git show HEAD~2 

jusqu'à ce que vous obteniez le commit requis. Pour que HEAD pointe vers cela, faites

git reset --hard HEAD~1

ou git reset --hard HEAD~2ou quoi que ce soit.

tonythomas01
la source
7
Avertissement obligatoire: ne faites pas cela si vous partagez votre branche avec d'autres personnes qui ont des copies des anciens commits, car l'utilisation d'une réinitialisation matérielle comme celle-ci les obligera à resynchroniser leur travail avec la branche nouvellement réinitialisée. Pour une solution qui explique en détail comment annuler en toute sécurité des validations sans perdre de travail avec une réinitialisation matérielle, consultez cette réponse .
2
Aussi, pour être clair, git show HEADéquivaut à simplement utiliser git log HEAD -1.
25

Si la situation est urgente et que vous voulez simplement faire ce que l'interrogateur a demandé de manière rapide et sale , en supposant que votre projet se trouve dans un répertoire appelé, par exemple, "mon projet":


RAPIDE ET SALE : selon les circonstances, rapide et sale peut en fait être très bon. Ce que ma solution ici, ce n'est PAS de remplacer irréversiblement les fichiers que vous avez dans votre répertoire de travail par des fichiers remontés / extraits des profondeurs du référentiel git qui se cachent sous votre répertoire .git / en utilisant des commandes git diaboliquement puissantes et diaboliquement puissantes, dont il y a beaucoup. VOUS N'AVEZ PAS À FAIRE UNE TELLE PLONGÉE EN MER PROFONDE POUR RÉCUPÉRER ce qui peut sembler être une situation désastreuse, et tenter de le faire sans une expertise suffisante peut s'avérer fatal .


  1. Copiez le répertoire entier et appelez-le autrement, comme "mon projet - copier". En supposant que vos fichiers de référentiel git ("repo") se trouvent dans le répertoire "mon projet" (leur emplacement par défaut, dans un répertoire appelé ".git"), vous aurez maintenant copié à la fois vos fichiers de travail et vos fichiers repo.

  2. Faites-le dans le répertoire "mon projet":

    .../my project $ git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

Cela ramènera l'état du dépôt sous "mon projet" à ce qu'il était lorsque vous avez fait ce commit (un "commit" signifie un instantané de vos fichiers de travail). Toutes les validations depuis lors seront perdues à jamais sous "mon projet", MAIS ... elles seront toujours présentes dans le référentiel sous "mon projet - copier" puisque vous avez copié tous ces fichiers - y compris ceux sous ... /. Git /.

Vous avez alors deux versions sur votre système ... vous pouvez examiner ou copier ou modifier les fichiers d'intérêt, ou autre, à partir du commit précédent. Vous pouvez supprimer complètement les fichiers sous "mon projet - copier", si vous avez décidé du nouveau travail puisque le commit restauré n'allait nulle part ...

La chose évidente si vous voulez continuer avec l'état du projet sans réellement supprimer le travail puisque cette validation récupérée est de renommer à nouveau votre répertoire: supprimez le projet contenant la validation récupérée (ou donnez-lui un nom temporaire) et renommez votre " mon projet - recopiez le "répertoire" dans "mon projet". Ensuite, essayez peut-être de comprendre certaines des autres réponses ici, et faites probablement un autre commit assez rapidement.

Git est une création brillante mais absolument personne n'est capable de simplement "le ramasser à la volée": aussi les gens qui essaient de l'expliquer beaucoup trop souvent supposent une connaissance préalable d'autres VCS [systèmes de contrôle de version] et plongent beaucoup trop loin trop tôt, et commettre d'autres crimes, comme utiliser des termes interchangeables pour «vérifier» - d'une manière qui semble parfois presque calculée pour dérouter un débutant.

Pour vous éviter beaucoup de stress, apprenez de mes cicatrices. Vous devez à peu près lire un livre sur Git - je recommanderais "Version Control with Git" . Faites-le plus tôt que tard. Si vous le faites, gardez à l'esprit qu'une grande partie de la complexité de Git vient de la ramification puis de la réémergence: vous pouvez ignorer ces parties dans n'importe quel livre. D'après votre question, il n'y a aucune raison pour que les gens vous aveuglent avec la science .

Surtout si, par exemple, c'est une situation désespérée et que vous êtes un débutant avec Git!

PS: Une autre pensée: il est (maintenant) en fait assez simple de conserver le dépôt Git dans un répertoire autre que celui contenant les fichiers de travail. Cela signifierait que vous n'auriez pas à copier l'intégralité du référentiel Git en utilisant la solution rapide et sale ci-dessus. Voir la réponse de Fryer en utilisant --separate-git-dir ici . Soyez averti , cependant: si vous avez un référentiel "répertoire séparé" que vous ne copiez pas et que vous effectuez une réinitialisation matérielle, toutes les versions postérieures à la réinitialisation seront perdues pour toujours, sauf si vous l'avez, comme vous le devez absolument, sauvegardez régulièrement votre référentiel, de préférence sur le Cloud (par exemple Google Drive ) entre autres.

Sur ce sujet de la "sauvegarde sur le Cloud", la prochaine étape est d'ouvrir un compte (gratuit bien sûr) avec GitHub ou (mieux à mon avis) GitLab . Vous pouvez ensuite effectuer régulièrement une git pushcommande pour mettre à jour votre repo Cloud "correctement". Mais encore une fois, parler de cela peut être trop tôt.

Mike rongeur
la source
23

C'est une autre façon de réinitialiser directement un commit récent

git stash
git stash clear

Il efface directement toutes les modifications que vous avez apportées depuis le dernier commit.

PS: Il y a un petit problème; il supprime également tous les changements de cachette que vous avez récemment enregistrés. Ce que je suppose dans la plupart des cas ne devrait pas avoir d'importance.

Réseaux de points
la source
REMARQUE: les nouveaux fichiers non ajoutés dans l'index ne sont pas stockés. Vous devez aussi les ajouter ou les supprimer manuellement.
andreyro
Pourquoi oh pourquoi vider la cachette? En plus d'être une non-solution, cela est en fait nocif. La lecture de la toute première phrase de la question invalide immédiatement la solution cachée (qui pourrait être utile UNIQUEMENT pour réinitialiser le LAST commit).
RomainValeri
22

Pour nettoyer complètement le répertoire d'un codeur contre certaines modifications accidentelles, nous avons utilisé:

git add -A .
git reset --hard HEAD

git reset --hard HEADSupprime simplement les modifications, mais ne supprime pas les "nouveaux" fichiers. Dans leur cas, ils avaient accidentellement glissé un dossier important quelque part au hasard, et tous ces fichiers étaient traités comme nouveaux par Git, donc ça reset --hardne l'a pas corrigé. En exécutant au git add -A .préalable, il les a explicitement tous suivis avec git, pour être effacés par la réinitialisation.

Chris Moschini
la source
21

Pour conserver les modifications de la validation précédente vers HEAD et passer à la validation précédente, procédez comme suit:

git reset <SHA>

Si des modifications ne sont pas requises par rapport à la validation précédente dans HEAD et que vous supprimez simplement toutes les modifications, procédez comme suit:

git reset --hard <SHA>
Vishnu Atrai
la source
20

Je pense que certaines personnes peuvent venir à cette question en voulant savoir comment annuler les modifications engagées qu'elles ont apportées à leur maître - c'est-à-dire tout jeter et revenir à l'origine / maître, auquel cas, procédez comme suit:

git reset --hard origin/master

/superuser/273172/how-to-reset-master-to-origin-master

Nevster
la source
18

Revert est la commande pour annuler les validations.

git revert <commit1> <commit2> 

Échantillon:

git revert 2h3h23233

Il est capable de prendre la plage de la tête comme ci-dessous. Ici 1 dit "annuler le dernier commit".

git revert HEAD~1..HEAD

et ensuite git push

Sireesh Yarlagadda
la source
14

Essayez de réinitialiser le commit souhaité -

git reset <COMMIT_ID>

(pour vérifier l'utilisation de COMMIT_ID git log)

Cela réinitialisera tous les fichiers modifiés à l'état non ajouté.

Maintenant, vous pouvez checkouttous les fichiers non ajoutés par

git checkout .

Cochez git logpour vérifier vos modifications.

MISE À JOUR

Si vous n'en avez qu'un seul et validez dans votre repo, essayez

git update-ref -d HEAD

optimistanoop
la source
13

Comme vos validations sont poussées à distance, vous devez les supprimer. Permettez-moi de supposer que votre branche est en développement et qu'elle est repoussée sur l' origine .

Vous devez d'abord supprimer le développement d' origine :

git push origin :develop (note the colon)

Ensuite, vous devez obtenir le développement du statut que vous souhaitez, je suppose que le hachage de validation est EFGHIJK:

git reset --hard EFGHIJK

Enfin, pousser à nouveau développer :

git push origin develop
George Ninan
la source
13

Mise en garde! Cette commande peut entraîner la perte de l'historique des validations si l'utilisateur a commis une erreur de validation incorrecte. Ayez toujours une sauvegarde supplémentaire de votre git quelque part ailleurs au cas où si vous faites des erreurs, que vous êtes un peu plus sûr. :)

J'ai eu un problème similaire et je voulais revenir à un commit précédent. Dans mon cas, je n'étais pas intéressé à conserver le nouveau commit, c'est pourquoi j'ai utilisé Hard.

Voici comment je l'ai fait:

git reset --hard CommitId && git clean -f

Cela reviendra sur le référentiel local, et ici après l'utilisation git push -fmettra à jour le référentiel distant.

git push -f
maytham-ɯɐɥʇʎɐɯ
la source
13

Dans GitKraken, vous pouvez le faire:

  1. Cliquez avec le bouton droit sur le commit que vous souhaitez réinitialiser, choisissez: Reset to this commit / Hard :

    Entrez la description de l'image ici

  2. Cliquez de nouveau avec le bouton droit sur le commit, choisissez: Nom de la branche actuelle / Push :

    Entrez la description de l'image ici

  3. Cliquez sur Force Push :

    Entrez la description de l'image ici

Obs. : Vous devez être prudent, car tout l'historique des validations après la réinitialisation matérielle est perdu et cette action est irréversible. Vous devez être sûr de ce que vous faites.

Ângelo Polotto
la source
11

Si vous voulez corriger une erreur dans le dernier commit, une bonne alternative serait d'utiliser la commande git commit --amend . Si le dernier commit n'est pointé par aucune référence, cela fera l'affaire, car il crée un commit avec le même parent que le dernier commit. S'il n'y a aucune référence au dernier commit, il sera simplement ignoré et ce commit sera le dernier commit. Il s'agit d'un bon moyen de corriger les validations sans annuler les validations. Cependant, il a ses propres limites.

Upul Doluweera
la source