Comment puis-je récupérer à partir d'un maître d'origine git push -f erroné?

92

Je viens de commettre la mauvaise source dans mon projet en utilisant l' --forceoption.

Est-il possible de revenir en arrière? Je comprends que toutes les branches précédentes ont été écrasées en utilisant l' -foption, donc j'ai peut-être foiré mes révisions précédentes.

David van Dugteren
la source
duplication possible de Est-il possible d'annuler git push -f?
cmbuckley

Réponses:

53

Git ne jette généralement rien, mais s'en remettre peut être difficile.

Si vous avez la bonne source, vous pouvez simplement la pousser dans la télécommande avec l' --forceoption. Git n'aura supprimé aucune branche à moins que vous ne le lui disiez. Si vous avez réellement perdu des commits, jetez un œil à ce guide utile pour récupérer des commits . Si vous connaissez le SHA-1 des commits que vous voulez, vous êtes probablement OK.

Meilleure chose à faire: sauvegardez tout et voyez ce qui se trouve encore dans votre référentiel local. Faites de même sur la télécommande si possible. Utilisez git fsckpour voir si vous pouvez récupérer des choses, et surtout NE PAS exécutergit gc .

Surtout, n'utilisez jamais l' --forceoption à moins que vous ne le pensiez vraiment, vraiment.

Cameron Skinner
la source
64
Vous pouvez très probablement simplement regarder les reflogs pour déterminer où se trouvaient à l'origine les branches distantes. Par exemple git reflog show remotes/origin/master,. Vous devriez pouvoir voir votre poussée là-dedans; le commit dans la ligne précédente est là où il était avant que vous ne le fassiez. Vous pouvez alors simplement pousser cette révision (avec --force) à l'origine, et revenir là où vous étiez!
Cascabel
@David: Oh. Vous n'avez pas mentionné dans votre question que vous n'aviez pas le repo. (C'est bien sûr quelque chose que vous ne voulez jamais faire.) Si vous avez un accès au système de fichiers là où vous avez poussé, vous pouvez toujours faire tout cela ici.
Cascabel
1
@David: Oui. Il est toujours bon d'avoir votre répertoire actuel dans votre invite pour éviter ce genre de chose.
Cascabel
1
@Jefromi Je pense que ce que vous avez dit là-bas est la vraie réponse: même avec une ancienne version (n'ayant pas git fetchédité depuis longtemps) vous pouvez afficher le reflog du côté de GitHub et récupérer!
nh2
1
Où est cette réponse de @Jefromi? Je ne vois pas cet utilisateur mentionné sur cette page en dehors de ce fil de commentaires.
Don McCurdy
47

Si vous connaissez le hachage de commit, c'est facile, recréez simplement votre branche.

5794458...b459f069 master -> master (forced update)

Supprimez la branche distante:

git push origin :master

puis recréez votre branche avec les commandes suivantes:

git checkout 5794458
git branch master
git push origin master
user1094125
la source
28

La solution est déjà mentionnée ici

# work on local master
git checkout master

# reset to the previous state of origin/master, as recorded by reflog
git reset --hard origin/master@{1}

# at this point verify that this is indeed the desired commit.
# (if necessary, use git reflog to find the right one, and
# git reset --hard to that one)

# finally, push the master branch (and only the master branch) to the server
git push -f origin master
Abdelhafid
la source
Merci, cela a fonctionné pour moi. Je n'avais pas accès à la suppression du maître, donc le commentaire approuvé a échoué.
Andi
Oui, et git reflog show remotes/origin/mastersi git reflog est nécessaire (comme mentionné par @Cascabel ci-dessus)
Josiah Yoder
2
C'est la bonne réponse, merci de vous connecter à la bonne.
Noitidart
6

Si vous n'êtes pas dans le dépôt local d'où provient le push forcé, au niveau origine / maître, il n'y a aucun moyen de récupérer. Mais si vous avez la chance d'utiliser GitHub ou GitHub for Enterprise , vous pouvez jeter un œil à l' API REST et récupérer le commit perdu en tant que correctif, exemple:

  1. Lister les événements et trouver le format long du commit sha1

https://api.github.com/repos/apache/logging-log4j2/events

  1. Téléchargez le commit perdu et récupérez le correctif associé dans le chemin json .files [] / patch

https://api.github.com/repos/apache/logging-log4j2/commits/889232e28f3863d2a17392c06c1dd8cac68485de

  1. Appliquer localement et pousser à nouveau

git apply patch.patch && git commit -m "commit restauré" && git push origin master

Pierrick HYMBERT
la source
4

Une autre façon de récupérer le commit perdu ou même de déterminer quels commits ont été perdus, si le push précédent ne provenait pas de votre dépôt local, est de regarder votre machine CI.

Si vous avez un travail qui teste la branche master après chaque commit (ou série de commits consécutifs), ce que vous devriez avoir, vous pouvez voir ce qu'il testait en dernier. C'est le commit que vous devez restaurer.

La machine CI peut même conserver un clone local du dépôt, à partir duquel vous pourrez peut-être effectuer cette récupération.

Source: livraison probablement continue: versions logicielles fiables grâce à l'automatisation de la construction, des tests et du déploiement (Addison-Wesley Signature Series (Fowler))

user7610
la source
3

Oui, vous pouvez récupérer les commits après git push -f your_branch

Texte du document :

Taillez les entrées plus anciennes que l'heure spécifiée. Si cette option n'est pas spécifiée, le délai d'expiration est tiré du paramètre de configuration gc.reflogExpire, qui à son tour est de 90 jours par défaut. --expire = toutes les entrées de pruneaux quel que soit leur âge; --expire = ne désactive jamais l'élagage des entrées accessibles (mais voir --expire-uneachable).

Vous pouvez donc faire:

1- git reflog

entrez la description de l'image ici

2- vous choisissez Head_Number voulez-vous récupérer avec git reset –hard HEAD@{HEAD-NUMBER}

entrez la description de l'image ici

3- vous pouvez voir tous les commits sur cette tête en git cherry -v branch_name

4- à la fin, vous devez forcer la poussée git push -f branch_name

OU

1- obtenir le nombre de SHA de votre client GIT (interface)

git reset --hard commit_SHA

2- force de poussée

git push -f your_branch

J'espère que cela t'aides

Jacob
la source
2

J'ai fait la même chose en annulant une dernière poussée pour un seul fichier. J'ai fini par revenir à l'état d'origine du référentiel. J'utilisais les commandes git de Linus car j'avais la copie locale sous Linux. Heureusement, cette copie était toujours intacte.

Tout ce que j'ai fait, c'est (après avoir frénétiquement fait quelques copies supplémentaires du repo local):

git add .
git status

(il disait que l'origine / master était en avance de 68 commits, très bien ... ce sont tous les commits que j'ai supprimés)

git remote set-url origin <GIT_SSH_URL>
git push

Et tout a été restauré tel qu'il était avant que je ne pousse avec force. La chose la plus importante à retenir est de ne jamais faire un checkout git. après avoir poussé avec force. Mais la meilleure pratique consiste à désactiver l'option push. Je ne l'utilise plus jamais. J'ai appris ma leçon !!

Pran
la source
0

Ici vous pouvez lire les décisions https://evilmartians.com/chronicles/git-push---force-and-how-to-deal-with-it

Le second m'a aidé. J'ai mal fait ces commandes

1) (some-branch) git pull -> correct command was git pull origin some-branch

2) (some-branch) git push -f origin some-branch

Après ces commandes, j'ai perdu trois commits. Pour les récupérer, j'ai regardé le terminal où j'ai mal fait 'git pull' et j'ai vu une sortie comme

60223bf ... 0b258eb une branche -> origine / une branche

Le deuxième hachage 0b258eb était exactement ce dont j'avais besoin. Alors, j'ai pris ce hachage et produire une commande

git push --force origin 0b258eb:some-branch
Andrey
la source
0

Pour les personnes dans de très mauvaises situations comme moi (par exemple, si vous obtenez des bad objecterreurs lors de l'exécution git reset --hard):

J'ai écrit un script appelé treesaver qui extrait tous vos fichiers de l'API GitHub en dernier recours. Voici comment l'utiliser:

  1. Clonez le treesaverscript et cdvers lui.
  2. Recherchez la SHAchaîne de l'arborescence que vous souhaitez restaurer en accédant à https://api.github.com/repos/<your_username_or_org>/<repo>/events.
  3. Dans la payloadpropriété correspondant à votre événement push, trouvez le commitvers lequel vous souhaitez revenir et cliquez sur son url.
  4. Sous commit.tree, copiez le treefichier url.
  5. Courez python3 main.py <tree_url> <path_to_save_to>.

Par exemple, dans mon cas, je lancerais:

python3 main.py https://api.github.com/repos/anthonykrivonos/my-repo/git/trees/1234567 .

Bien sûr, les RP sont les bienvenus.

Anthony Krivonos
la source