Réinitialisation de la télécommande à un certain commit

709

Je souhaite ignorer toutes les modifications effectuées après la validation <commit-hash>. J'ai donc fait:

git reset --hard <commit-hash>

Maintenant, je veux faire de même avec ma télécommande. Comment puis-je faire ceci? J'ai fait quelques commits (et push) après <commit-hash>et je veux juste les supprimer tous. C'est juste que quelque chose s'est terriblement mal passé et je ne veux pas empirer les choses. ; (

Je veux essentiellement pour revenir en arrière mon origin/masterà<commit-hash>

nacho4d
la source
3
Êtes-vous sûr que votre origin/mastern'a pas été tiré et poussé par d'autres utilisateurs? La modification de l'historique d'un référentiel public (c'est-à-dire non local) est quelque chose que vous souhaitez éviter à tout moment.
vindia
Copie possible de Comment annuler plusieurs validations git?
Michael Freidgeim

Réponses:

1252

En supposant que votre branche est appelée masterici et à distance, et que votre télécommande est appelée, originvous pouvez faire:

 git reset --hard <commit-hash>
 git push -f origin master

Cependant, vous devez éviter de le faire si quelqu'un d'autre travaille avec votre référentiel distant et a retiré vos modifications. Dans ce cas, il serait préférable de revenir sur les commits que vous ne voulez pas, puis de pousser comme d'habitude.

Mise à jour: vous avez expliqué ci-dessous que d'autres personnes ont retiré les modifications que vous avez poussées, il est donc préférable de créer un nouveau commit qui annule toutes ces modifications . Il y a une belle explication de vos options pour ce faire dans cette réponse de Jakub Narębski . La méthode la plus pratique dépend du nombre de validations que vous souhaitez annuler et de la méthode qui vous convient le mieux.

Depuis votre question, il est clair que vous avez déjà utilisé git reset --hardpour réinitialiser votre masterbranche, vous devrez peut-être commencer par utiliser git reset --hard ORIG_HEADpour ramener votre branche à son emplacement précédent. (Comme toujours avec git reset --hard, assurez-vous que git statusc'est propre, que vous êtes sur la bonne branche et que vous êtes git reflogun outil pour récupérer des ORIG_HEADvalidations apparemment perdues.) Vous devriez également vérifier que cela pointe vers la bonne validation, avec git show ORIG_HEAD.

Dépannage:

Si vous obtenez un message du type " ! [Rejeté à distance] a60f7d85 -> maître (crochet de pré-réception refusé) "

vous devez alors autoriser la réécriture de l'historique des branches pour la branche spécifique. Dans BitBucket, par exemple, il est dit "La réécriture de l'historique des branches n'est pas autorisée". Il y a une case à cocher nommée Allow rewriting branch historyque vous devez cocher.

Mark Longair
la source
21
Danger danger: cette réinitialisation suppose que la branche (de suivi ) correspondante est actuellement extraite et qu'il n'y a aucune modification non validée que vous vouliez conserver. Utilisez git update-refau lieu dereset --hard ; il vous permettra de faire la même chose sans avoir un arbre de travail / vérifié branche
sehe
3
Je vois. Il a été poussé et changé par d'autres. Donc je devrais utiliser revert mais disons que je veux revenir sur les 4 derniers commits donc je dois le faire git revert comit1; git push; git revert comit2; git push; ...ou simplement git revert commit4; git push?
nacho4d
1
@ nacho4d: vous n'avez pas besoin de pousser après chaque retour - il y a une belle description de ce qu'il faut faire dans cette réponse de Jakub Narębski . Vous devez annuler chaque commit en arrière - le simple fait de git revert commit4créer un nouveau commit qui annule uniquement les modifications introduites dans commit4. Comme le souligne la réponse que j'ai liée à, vous pouvez les regrouper en un seul commit.
Mark Longair
1
@Mark J'ai déjà exécuté git reset --hardmais j'ai supprimé mon local et retiré à nouveau de l'origine, donc je peux faire git revert ...mon doute maintenant: dois-je revenir sur chaque commit et pousser (un par un) ou simplement annuler le premier commit après le bon engagement seulement?
nacho4d
1
@sehe: il est difficile à utiliser car vous devez utiliser le nom complet de la référence, et il est donc facile pour les gens de joncher leur .gitrépertoire avec des références qu'ils ne voulaient pas créer. J'avais cependant tort de dire qu'il n'y a pas de contrôles de sécurité. Vous pouvez trouver la classification en commandes "plomberie" et "porcelaine" dans la page de manuel git .
Mark Longair
123

Utilisez les autres réponses si cela ne vous dérange pas de perdre les modifications locales.Cette méthode peut toujours détruire votre télécommande si vous choisissez le mauvais hachage de validation pour y revenir.

Si vous souhaitez simplement faire de la correspondance à distance un commit qui se trouve n'importe où dans votre référentiel local:

  1. Ne pas faire une remise à zéro.
  2. Utilisez git logpour trouver le commit auquel vous voulez que la télécommande se trouve. git log -ppour voir les changements ou git log --graph --all --oneline --decoratepour voir un arbre compact.
  3. Copiez le hachage du commit ou sa balise, ou le nom de sa branche s'il s'agit de l'astuce.
  4. Exécutez une commande comme:

    git push --force <remote> <commit-ish>:<the remote branch>
    

    par exemple

    git push --force origin 606fdfaa33af1844c86f4267a136d4666e576cdc:master
    

    ou

    git push --force staging v2.4.0b2:releases
    

J'utilise un alias ( git go) pratique pour afficher l'historique comme à l'étape 2, qui peut être ajouté comme suit:

    git config --global alias.go 'log --graph --all --decorate --oneline'`
Walf
la source
3
Le graphique était une très bonne astuce, je viens d'ajouter -5 pour obtenir uniquement les n derniers commits, c'était un autre arbre énorme. Éviter également la réinitialisation est exactement ce que je cherchais. Génial
AlexanderD
@AlexanderD Vous pouvez également ajouter l'alias à Git plutôt qu'à votre shell, donc cela fonctionne partout. Git comprend ces alias et ces tabulations à partir de la commande complète afin que vous puissiez ajouter des arguments. git config --global alias.graph 'log --graph --all --decorate --oneline'est moins salissant et vous pouvez toujours le limiter, par exemple:git graph -5
Walf
C'est parfait. J'ai toujours foiré mon local. C'était exactement ce dont j'avais besoin après avoir poussé accidentellement ma mise en scène pour vivre :( Merci!
Jake
1
Sous Windows, entrez qpour quitter le journal git. 2 minutes je ne reviendrai jamais.
dst3p
1
@ dst3p C'est sur chaque plate-forme, mec. Le programme de téléavertisseur est généralement lesset qest le moyen normal de le quitter. Git Bash est comme un terminal * nix.
Walf
63

J'ai résolu un problème comme le vôtre par ces commandes:

git reset --hard <commit-hash> 
git push -f <remote> <local branch>:<remote branch> 
Ibrohim Ermatov
la source
13

Sur GitLab, vous devrez peut-être définir votre branche sur non protégé avant de le faire. Vous pouvez le faire dans [repo]> Paramètres> Référentiel> Branches protégées. Ensuite, la méthode de la réponse de Mark fonctionne.

git reset --hard <commit-hash>
git push -f origin master
dudasaus
la source
10

Si vous voulez une version précédente du fichier, je recommanderais d'utiliser git checkout.

git checkout <commit-hash>

Faire cela vous renverra dans le temps, cela n'affecte pas l'état actuel de votre projet, vous pouvez venir sur mainline git checkout mainline

mais lorsque vous ajoutez un fichier dans l'argument, ce fichier vous est ramené d'une heure précédente à l'heure de votre projet actuel, c'est-à-dire que votre projet actuel est modifié et doit être validé.

git checkout <commit-hash> -- file_name
git add .
git commit -m 'file brought from previous time'
git push

L'avantage de ceci est qu'il ne supprime pas l'historique, et ne rétablit pas non plus les modifications d'un code particulier (git revert)

Vérifiez plus ici https://www.atlassian.com/git/tutorials/undoing-changes#git-checkout

priya khokher
la source
Ceci est une excellente réponse: cela fonctionne, période et est très sûr; si vous vous trompez, il est facile de revenir en arrière.
bob
8

Mes deux cents aux réponses précédentes: si

git push --force <remote> <the-hash>:<the remote branch>

ne fonctionne toujours pas, vous pouvez modifier <your-remote-repo>.git/configla section de réception du fichier:

[receive]
  #denyNonFastforwards = true
  denyNonFastforwards = false
badbishop
la source
Il est utile de savoir comment configurer une télécommande pour permettre des poussées non rapides, car la plupart des réponses semblent supposer un service distant comme github ou bitbucket.
strongbutgood
2

Si votre branche n'est pas en développement ou en production, la façon la plus simple d'y parvenir est de réinitialiser un certain commit localement et de créer une nouvelle branche à partir de là. Vous pouvez utiliser:

git checkout 000000

(où 000000 est l'ID de validation où vous voulez aller) dans votre branche problématique, puis créez simplement une nouvelle branche:

git remote add [nom_de_votre_remote]

Ensuite, vous pouvez créer un nouveau PR et tout fonctionnera bien!

Gerardo Suarez
la source
1

Faites une chose, obtenez le numéro SHA du commit. comme 87c9808 et ensuite,

  1. déplacez-vous, c'est votre tête vers le commit spécifié (en faisant git reset --hard 89cef43 // mentionnez votre numéro ici)
  2. Ensuite, faites quelques changements dans un fichier aléatoire, de sorte que le git vous demandera de le valider localement puis à distance. Ainsi, ce que vous devez faire maintenant est. après avoir appliqué le changement git commit -a -m "commit commit"
  3. Poussez maintenant le commit suivant (s'il a été validé localement) par git push origin master
  4. Maintenant, ce que Git vous demandera, c'est que

erreur: échec de l'envoi de certaines références à « https://github.com/YOURREPOSITORY/AndroidExperiments.git ». Indice: les mises à jour ont été rejetées car la pointe de votre branche actuelle se trouve derrière l'indice: son homologue distant. Intégrez les modifications à distance (par exemple indice: 'git pull ...') avant de pousser à nouveau. **

  1. Donc maintenant ce que vous pouvez faire c'est

git push --force origin master

  1. Et donc, j'espère que ça marche :)
Siddharth Choudhary
la source
1

Sourcetree: réinitialiser la télécommande à un certain commit

  1. Si vous avez poussé un mauvais commit sur votre télécommande (origine / fonctionnalité / 1337_MyAwesomeFeature) comme l'image ci-dessous

Aller aux télécommandes

  1. Accédez à Télécommandes> origine> fonctionnalité> 1337_MyAwesomeFeature
  2. Faites un clic droit et choisissez «Supprimer l'origine / la fonction / 1337_MyAwesomeFeature» (ou changez le nom si vous voulez une sauvegarde et ignorez l'étape 4.)
  3. Cliquez sur "Forcer la suppression" et "OK".

entrez la description de l'image ici entrez la description de l'image ici

  1. Sélectionnez votre ancien commit et choisissez "Réinitialiser la branche actuelle sur ce commit"
  2. Choisissez le mode que vous souhaitez avoir (Difficile si vous ne voulez pas vos dernières modifications) et "OK".

entrez la description de l'image ici entrez la description de l'image ici

  1. Poussez ce commit vers une nouvelle origine / fonctionnalité / 1337_MyAwesomeFeature entrez la description de l'image ici

  2. Votre branche de fonctionnalité locale et votre branche de fonctionnalité distante sont désormais sur le commit précédent (de votre choix) entrez la description de l'image ici

Joel Wiklund
la source