Revenir à un ancien commit Git dans un dépôt public


802

Comment puis-je faire pour revenir à un commit spécifique dans git ?

La meilleure réponse que quelqu'un pourrait me donner était d'utiliser git revertX fois jusqu'à ce que j'atteigne le commit souhaité.

Alors disons que je veux revenir à un commit qui a 20 ans, je devrais l'exécuter 20 fois.

Existe-t-il un moyen plus simple de procéder?

Je ne peux pas utiliser la réinitialisation car ce référentiel est public.


1
git revert <commit> ne fonctionne pas?
miku

8
Comme indiqué dans ma question, cela ne m'aide vraiment pas si je veux revenir à quelque chose d'il y a 20 ans.
David

7
Cette question a été assez bien répondu ici stackoverflow.com/questions/4114095/…
user7610

4
Ce que vous entendez par «reculer» n'est pas clair. Cela signifie-t-il que vous souhaitez basculer temporairement votre copie de travail vers une révision particulière? Ou vous souhaitez rétablir définitivement l'historique de votre référentiel à une certaine révision?

1
Vous devez accepter une réponse et éventuellement voter pour toutes les autres réponses que vous aimez.
Nabil Kadimi

Réponses:


1194

Essaye ça:

git checkout [revision] .

[revision]est le hachage de validation (par exemple:) 12345678901234567890123456789012345678ab.

N'oubliez pas le .à la fin, très important. Cela appliquera les modifications à l'arbre entier. Vous devez exécuter cette commande dans la racine du projet git. Si vous êtes dans un sous-répertoire, cette commande ne modifie que les fichiers du répertoire actuel. Alors engagez-vous et vous devriez être bon.

Vous pouvez annuler cela en

git reset --hard 

qui supprimera toutes les modifications du répertoire de travail et de la zone de transit.


7
@AlexReisner Cette période aux extrémités du répertoire dans lequel vous vous trouvez actuellement, qui n'est pas nécessairement le projet git entier, n'est-ce pas? Si vous vouliez appliquer les modifications à l'ensemble du projet, utiliseriez-vous à la place ': /' comme dans 'git add: /', si vous n'étiez pas actuellement dans la racine du projet git?
MSpreij

10
remarque: si vous avez ajouté de nouveaux fichiers à votre projet depuis, cela ne les supprimera pas. Ainsi, lorsque vous allez construire (en fonction de votre plate-forme), vous pouvez toujours obtenir des erreurs. Supprimez les nouveaux fichiers et c'est parti.
TheWestIsThe ...

6
@MSpreij Vous devez exécuter cette commande à la racine du projet git. Si vous êtes dans un sous-répertoire, cette commande ne modifie que les fichiers du répertoire actuel.
volatilevar

3
C'est génial quand vous pouvez cloner un projet dans un autre répertoire et utiliser git checkout [revision]. pour revenir à une révision spécifique, puis la comparer avec le même projet dans un autre répertoire. Économise beaucoup de temps.
Donato

4
Merde, j'ai oublié le "." quels dommages ai-je causés à mon référentiel?
Hibou

196

Pour revenir à une validation spécifique:

git reset --hard commit_sha

Pour annuler 10, vous validez:

git reset --hard HEAD~10

Vous pouvez utiliser "git revert" comme dans le post suivant si vous ne voulez pas réécrire l'historique

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


4
seule différence entre cette approche et "git checkout [revision]". est que ce dernier conserve les révisions.
deeshank

53
Cette réponse est FAUX car OP déclare spécifiquement "Je ne peux pas utiliser la réinitialisation car ce dépôt est public"
Yarin

4
Si le dépôt est public, je pense qu'il n'y a aucun moyen d'annuler la validation sur le référentiel public sans utiliser la force push (git push -f) car cela affectera les personnes qui ont apporté les modifications avant la restauration. Ainsi, la réinitialisation peut également être utilisée dans le bac à sable local d'un dépôt public.
Naga Kiran

4
C'est génial que cela évite une tête détachée! Exactement ce que je cherchais.
cyber-moine

1
Dans mon cas, cela a fonctionné, puis utilisez `` git pull '' pour avancer rapidement en arrière après avoir testé les régressions, etc.
Peter Quiring

86

Eh bien, je suppose que la question est, que voulez-vous dire par «reculer»? Si vous ne le pouvez pas, resetcar il est public et que vous souhaitez conserver l'historique des validations intact, voulez-vous simplement que votre copie de travail reflète un commit spécifique? Utilisez git checkoutet le hachage de validation.

Edit: Comme cela a été souligné dans les commentaires, l'utilisation git checkoutsans spécifier de branche vous laissera dans un état "sans branche". Utilisez cette git checkout <commit> -b <branchname>option pour passer à une succursale ou git checkout <commit> .pour passer à la succursale actuelle.


Cela ne vous met-il pas dans l'état étrange de «Pas actuellement sur une branche»? Comment validez-vous les modifications pour terminer la restauration?
Alex Reisner

Eh bien, je suggère simplement l'utilisation de git checkout- il est libre de vérifier dans n'importe quelle branche (actuelle ou nouvelle) qu'il souhaite. Je mettrai à jour ma réponse afin qu'elle ne soit pas ambiguë.
Ben

2
J'ai essayé mais je ne pense pas que ce soit la bonne façon de le faire car cela laisse des fichiers stagnants. Cela ne supprime pas les fichiers qui n'étaient pas dans ce dernier commit.
David

3
Si vous êtes dans un répertoire de travail et que vous restez en maître, vous devez git resetsupprimer ces fichiers, ce que vous dites ne pas vouloir faire. Essayez de le faire dans une branche distincte:, git checkout <commit> -b <branchname>vous n'aurez pas de fichiers stagnants dans cette branche .
Ben

2
Le problème avec l'utilisation checkoutest qu'elle ne supprimera pas les fichiers qui ont été ajoutés lors d'une validation précédente.

42

L'affiche originale indique:

La meilleure réponse que quelqu'un pourrait me donner était d'utiliser git revertX fois jusqu'à ce que j'atteigne le commit souhaité.

Alors disons que je veux revenir à un commit qui a 20 ans, je devrais l'exécuter 20 fois.

Existe-t-il un moyen plus simple de procéder?

Je ne peux pas utiliser la réinitialisation car ce dépôt est public.

Il n'est pas nécessaire d'utiliser git revertX fois. git revertpeut accepter une plage de validation comme argument, vous n'avez donc besoin de l'utiliser qu'une seule fois pour rétablir une plage de validations. Par exemple, si vous souhaitez annuler les 20 derniers commits:

git revert --no-edit HEAD~20..

La plage de validation HEAD~20..est abrégée HEAD~20..HEADet signifie «commencer à partir du 20 e parent de la validation HEAD, et rétablir toutes les validations suivantes jusqu'à HEAD».

Cela ramènera les 20 derniers commits, en supposant qu'aucun d'entre eux ne soit un commit de fusion. S'il y a des validations de fusion, vous ne pouvez pas toutes les annuler en une seule commande, vous devrez les annuler individuellement avec

git revert -m 1 <merge-commit>

Notez également que j'ai testé en utilisant une plage avec git revertgit version 1.9.0. Si vous utilisez une ancienne version de git, l'utilisation d'une plage avec git revertpeut ou peut ne pas fonctionner.

Dans ce cas, git revertest préférable à git checkout.

Notez que contrairement à cette réponse qui dit d'utilisergit checkout , git revert supprimera en fait tous les fichiers qui ont été ajoutés dans l'un des commits que vous annulez , ce qui en fait la bonne façon d'annuler une gamme de révisions.

Documentation


Remarque : cela crée un nouveau commit avec les modifications annulées. Parfait pour la question d'OP. Mais assurez-vous que c'est ce que vous voulez. (Les exemples dans le document git-revert lié à ci-dessus sont excellents.) Si vous souhaitez plutôt enquêter sur les validations antérieures (c'est-à-dire avant de choisir le commit sur lequel revenir), utilisez l'option de paiement mentionnée dans d'autres réponses, en gardant à l'esprit les commentaires des autres. fait sur les fichiers supprimés.
SherylHohman

@SherylHohman Revenir à un commit précédent ne crée pas de nouveau commit. Je ne peux pas imaginer ce que tu veux dire ici.

27

Étape 1: récupérer la liste des validations:

git log

Vous obtiendrez une liste comme dans cet exemple:

[Comp:Folder User$ git log
commit 54b11d42e12dc6e9f070a8b5095a4492216d5320
Author: author <author@gmail.com>
Date:   Fri Jul 8 23:42:22 2016 +0300

This is last commit message

commit fd6cb176297acca4dbc69d15d6b7f78a2463482f
Author: author <author@gmail.com>
Date:   Fri Jun 24 20:20:24 2016 +0300

This is previous commit message

commit ab0de062136da650ffc27cfb57febac8efb84b8d
Author: author <author@gmail.com>
Date:   Thu Jun 23 00:41:55 2016 +0300

This is previous previous commit message
...

Étape 2: copiez le hachage de validation requis et collez-le pour le paiement:

git checkout fd6cb176297acca4dbc69d15d6b7f78a2463482f

C'est tout.


11
git read-tree -um @ $commit_to_revert_to

le fera. C'est "git checkout" mais sans mettre à jour HEAD.

Vous pouvez obtenir le même effet avec

git checkout $commit_to_revert_to
git reset --soft @{1}

si vous préférez enchaîner des commandes pratiques.

Ceux-ci vous laissent avec votre arbre de travail et votre index dans l'état souhaité, vous pouvez simplement git committerminer.


C'est la seule approche simple qui a fonctionné comme un charme! J'ai vérifié à partir de la tête, j'ai exécuté cette commande et elle a réussi à supprimer les fichiers ajoutés que nous avions introduits et à annuler toutes les modifications. Excellent.
kamranicus

6

Vous voulez le mode HEAD détaché?

Si vous souhaitez faire reculer X fois un certain commit avec une TÊTE DÉTACHÉE (ce qui signifie que vous ne pouvez rien gâcher), alors certainement, utilisez ce qui suit:

(remplacez X par le nombre de commits que vous souhaitez revenir en arrière)

git checkout HEAD~X

IE pour revenir en arrière un commit:

git checkout HEAD~1

1
Je supprimerais la partie avec ... difficile à croire ... Cela semble personnel, et aussi quelqu'un l'a mentionné dans un commentaire ci-dessus, et dans @ken aussi dans sa réponse.
meJustAndrew

@meJustAndrew C'est, tant de réponses sur SO qui déroutent les gens, c'est assez ennuyeux.
Karl Morrison

Quelle réponse simple et directe.
Ammad

2

Disons que vous travaillez sur un projet et après une journée ou deux. Vous remarquez qu'une fonctionnalité vous donne toujours des erreurs. Mais vous ne savez pas quel changement vous avez provoqué qui a provoqué l'erreur. Vous devez donc pêcher les commits de travail précédents. Pour revenir à un commit spécifique:

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 .

Ok, donc ce commit fonctionne pour vous. Plus d'erreur. Vous avez identifié le problème. Vous pouvez maintenant revenir au dernier commit:

git checkout 792d9294f652d753514dc2033a04d742decb82a5 .

Et extraire un fichier spécifique avant qu'il ne cause l'erreur (dans mon cas, j'utilise l'exemple Gemfile.lock):

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 -- /projects/myproject/Gemfile.lock

Et c'est une façon de gérer les erreurs que vous avez créées dans les validations sans réaliser les erreurs plus tard.


2

Vous pouvez trouver l'ID de validation lié à chaque validation dans la section des validations de GitHub / BitBucket / Gitlab. C'est très simple, supposons que votre ID de validation soit 5889575, puis si vous souhaitez revenir à cette partie de votre code, il vous suffit de taper

git checkout 5889575 .

Cela vous amènera à ce moment dans votre code.


1

Je ne sais pas ce qui a changé, mais je ne parviens pas à extraire un commit spécifique sans l'option --detach. La commande complète qui a fonctionné pour moi était: git checkout --detach [commit hash]

Pour revenir de l'état détaché, j'ai dû vérifier ma succursale locale: git checkout master


Vérifier masterrésout le problème de rester détaché, tout en faisant git reset --hardou en git checkout -- .travaillant mais resté détaché
DarkCygnus

0

Voici un exemple pour le faire

    cd /yourprojects/project-acme 


    git checkout efc11170c78 .
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.