Restauration du référentiel git local et distant par 1 commit


188

J'ai lu des articles similaires sur ce sujet et je ne peux pas pour la vie de moi comprendre comment le faire correctement.

J'ai archivé environ 1000 fichiers dont je ne veux pas et je préfère ne pas avoir à passer par 1by1 et à les supprimer tous du dépôt.

  • J'ai une mastersuccursale éloignée .
  • J'ai la mastersuccursale locale .

Ils sont tous les deux à la même révision.

Je veux restaurer ma télécommande d'un commit.

Dites que mon histoire masterest A--B--C--D--E.
Je souhaite restaurer mon fichier local sur D.
Ensuite, poussez-le sur remote pour que mon hachage actuel soit D à la fois distant et local.

J'ai des problèmes pour faire ça.
J'utilise Git Tower mais je suis à l'aise avec la ligne de commande. De l'aide?

MISE À JOUR: Grands commentaires ci-dessous. L'utilisation d'une réinitialisation semble être partiellement déconseillée, surtout si le référentiel est partagé avec d'autres utilisateurs. Quelle est la meilleure façon d'annuler les modifications du commit précédent sans utiliser une réinitialisation matérielle ? Y a-t-il un moyen?


J'ai mis à jour ma réponse pour "annuler les modifications du commit précédent sans utiliser de réinitialisation matérielle".
VonC

3
À utiliser git revertpour se passer de réinitialisations matérielles et sans déranger les utilisateurs.
user562374

2
Double

Faire reculer la télécommande est ce qui est déconseillé, mais si c'est ce que vous voulez faire, faites-le. Il y a des centaines de façons de faire cela, mais le résultat serait le même côté serveur.
FelipeC

Réponses:


307

Si personne n'a encore retiré votre repo distant, vous pouvez changer votre branche HEAD et forcer le pousser vers ledit repo distant:

git reset --hard HEAD^ 
git push -f 

(ou, si vous avez un accès direct au repo distant, vous pouvez modifier sa référence HEAD même s'il s'agit d'un repo nu )

Notez, comme commenté par alien-technology dans les commentaires ci - dessous , sous Windows (session CMD), vous auriez besoin de ^^:

git reset --hard HEAD^^
git push -f 

Mise à jour depuis 2011: l'
utilisation git push --force-with-lease( que je présente ici , introduite en 2013 avec Git 1.8.5) est plus sûre.

Voir la réponse de Schwern pour illustration.


Et si quelqu'un a déjà retiré le repo? Que ferais-je alors?

Ensuite, je suggérerais quelque chose qui ne réécrit pas l'histoire:

  • git revert localement votre dernier commit (création d'un nouveau commit qui inverse ce que le commit précédent a fait)
  • pousser le 'retour' généré par git revert.

1
Et si quelqu'un a déjà retiré le repo? Que ferais-je alors?
Jamis Charles

1
@gwho crée une branche? Non, cela déplace la tête d'une branche, mais vous êtes toujours dans la même branche. Cependant, comme la poussée n'est plus une avance rapide, oui, vous devez forcer cette poussée.
VonC

1
y a-t-il un moyen de savoir si quelqu'un a retiré le repo?
Pinkerton

4
Sous Windows, le caractère ^ est utilisé pour la continuation de ligne et pour échapper un caractère, en faisant la commande: git reset --hard HEAD ^^
Alien Technology

1
@AlienTechnology En utilisant Powershell, sous Windows 10, je n'avais qu'à taper reset --hard HEAD^et non reset --hard HEAD^^à réinitialiser le dernier commit.
Gaspacchio

58

Définissez la branche locale une révision en arrière ( HEAD^signifie une révision en arrière):

git reset --hard HEAD^

Poussez les modifications à l'origine:

git push --force

Vous devrez forcer le push car sinon, git reconnaîtrait que vous êtes en retard originpar un commit et rien ne changera.

Le faire avec --forcedit à git d'écraserHEAD dans le référentiel distant sans respecter aucune avancée.


1
Je suggérerais de ne pas appeler cela un retour, car c'est un terme spécifique avec une signification très différente dans git.
Cascabel

@Jefromi: Merci pour l'indice. Édité.
eckes

Très bonne réponse. J'ai lu que l'utilisation d'une réinitialisation semble être partiellement déconseillée, surtout si le référentiel est partagé avec d'autres utilisateurs. Existe-t-il un moyen plus propre de le faire, qui annule toutes les modifications de votre commit précédent?
Jamis Charles

Faites attention! Stockez vos modifications non validées ou vos modifications perdues
Nosov Pavel

C'est super. Alors, cela signifie-t-il que lorsque nous le faisons git push origin master, Git est capable de créer un nouveau commit à distance parce que la branche locale est en avance d'au moins une fois? En outre, ce dernier doit être substantiellement différent de ce que pointe la tête du repo distant?
MadPhysicist

18

Si vous voulez revenir au dernier commit écoutez:

Étape 1:

Vérifiez vos engagements locaux avec des messages

$ git log

Étape 2:

Supprimer le dernier commit sans réinitialiser les modifications de la branche locale (ou du maître)

$ git reset HEAD^

OU si vous ne voulez pas que les derniers fichiers de commit et les mises à jour écoutent

$ git reset HEAD^ --hard

Étape 3:

Nous pouvons mettre à jour les fichiers et les codes et à nouveau besoin de pousser avec force, cela supprimera le commit précédent. Il conservera un nouveau commit.

$ git push origin branch -f

C'est tout!


Ce n'est pas annuler un commit, c'est en remplacer un. S'il vous plaît, ne nous confondez pas avec les novices en abusant des termes conventionnels.
Suncat2000

7

En entrant la commande ci-dessous, vous pouvez voir votre historique de validation git -

$ git log

Disons que votre historique sur cette branche particulière est comme - commit_A, commit_B, commit_C, commit_D. Où, commit_D est le dernier commit et c'est là que HEAD reste. Maintenant, pour supprimer votre dernier commit local et distant, vous devez procéder comme suit:

Étape 1: supprimer le dernier commit localement par -

$ git reset --hard HEAD ~

Cela changera votre commit HEAD en commit_C

Étape 2: Poussez votre changement pour un nouveau commit HEAD à distance

$ git push origin + HEAD

Cette commande supprimera le dernier commit de la télécommande.

PS cette commande est testée sur Mac OSX et devrait également fonctionner sur d'autres systèmes d'exploitation (sans prétendre à d'autres OS)



3

Voici une version mise à jour de la procédure qui est plus sûre.

git reset --hard HEAD^ 
git push --force-with-lease

git push -fremplacera sans discernement le référentiel distant par vos propres modifications. Si quelqu'un d'autre a poussé des changements, ils seront perdus.git push --force-with-leasene poussera votre rebase que si le référentiel est comme prévu. Si quelqu'un d'autre a déjà poussé, votre push échouera.

Voir –force considérée comme nuisible; comprendre git's –force-with-bail .

Je recommande d'aliaser ceci comme repush = push --force-with-lease.

Et si quelqu'un a déjà retiré le repo? Que ferais-je alors?

Dites-leur git pull --rebase=merges. Au lieu d'un git fetch originet git merge origin/masteril le fera git fetch originet git rebase -r origin/master. Cela réécrira tous leurs changements locaux masteren plus du nouveau rebasé origin/master. -rconservera toutes les fusions qu'ils ont pu effectuer.

Je recommande d'en faire le comportement par défaut pour tirer. Il est sûr, gère le rebasage des autres et entraîne moins de fusions inutiles.

[pull]
        rebase = merges

1
D'accord et voté. Pour ma défense, mon ancienne réponse de 2011 a été écrite deux ans avant l'introduction de l' --force-with-leaseoption.
VonC le

Je pensais l'avoir déjà fait (hier): stackoverflow.com/posts/4647362/revisions
VonC

1

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

git reset --hard HEAD^
git push -f <remote> <local branch>:<remote branch> 


0

Je voulais juste supprimer le dernier commit de l'historique des commit distant et effacer également. Ce qui suit a fonctionné comme un charme

git reset --hard HEAD^ 
git push -f 

Mais en quoi «ce qui suit» est-il différent de ma réponse ci - dessus ?
VonC

0

La façon de réinitialiser la tête et de revenir au commit précédent est de

$ git reset HEAD^ --hard
$ git push <branchname> -f

Mais parfois, cela peut ne pas être accepté dans la branche distante:

To ssh:<git repo>
 ! [rejected]        develop -> develop (non-fast-forward)
error: failed to push some refs to 'ssh:<git repo>'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

alors l'autre façon de faire est

git revert HEAD
git push <remote branch>

Cela fonctionne très bien.

REMARQUE: rappelez-vous si l' git push -f <force>échec et que vous essayez de revenir en arrière. Faites un git pullavant, pour que la télécommande et le local soient synchronisés, puis essayez git revert.
Vérifiez avec git logpour vous assurer que le distant et le local sont au même point de validation avec le même SHA1.

git revert 
A --> B --> C -->D
A--> B --> C --> D --> ^D(taking out the changes and committing reverted diffs)

0

sur le maître local

git reflog
-- this will list all last commit
  e.g Head@{0} -- wrong push
      Head@{1} -- correct push  
git checkout Head@{1} .
  -- this will reset your last modified files

git status 
git commit -m "reverted to last best"
git push origin/master

Pas besoin de s'inquiéter si l'autre a tiré ou non.

Terminé!


0

Si vous souhaitez uniquement supprimer le dernier commit du référentiel distant sans gâcher votre référentiel local, voici un one-liner:

git push origin +origin/master~:master

Cela utilise la syntaxe suivante:

git push <remote> <refspec>

Voici, <remote>est originet <refspec>a la structure suivante:

+origin/master~:master

Les détails peuvent être trouvés dans git-push(1). La précédente +signifie "forcer cette ref", et l'autre partie signifie "de origin/master~à master(de la télécommande origin)". Il n'est pas difficile de savoir que origin/master~c'est le dernier commit avant origin/master, non?


0

pour moi fonctionne ces deux commandes:

git checkout commit_id
git push origin +name_of_branch

0

Vous pouvez également faire ceci:

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

et faites réinitialiser tous les autres utilisateurs qui ont reçu les derniers mauvais commits:

git reset --hard origin/master
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.