git push –force et comment y faire face

Vous êtes-vous déjà retrouvé dans une situation où une mauvaise commande git a fait des ravages sur le repo de votre projet ? Les gens font des erreurs, et parfois ces erreurs peuvent coûter des heures de temps à votre équipe. Dans ce tutoriel, nous allons vous montrer comment récupérer rapidement d’une git push --forcemalheureuse.

Ne soyons pas trop confiants. Tôt ou tard, cela va se produire. En travaillant avec plusieurs remotes dans le même dépôt git, vous finirez par git push --force dans master (ou une autre branche importante avec laquelle il ne faut jamais jouer).

Cela peut arriver, par exemple, lors du déploiement avec Deis ou Heroku qui utilisent des remotes git distincts pour construire et déployer une application. Après une longue journée de travail, il est incroyablement facile d’exécuter git push --force au lieu de l’habituel git push --force deis master.

Oops ! En un clin d’œil, vos coéquipiers ont perdu tous leurs derniers travaux. Il est temps d’affronter leur rage.

Mais, comme nous le dit un excellent guide, NE PANIQUEZ PAS ! La bonne chose est que vous utilisez git, et cela signifie que tout peut être réparé.

Dans le meilleur des cas : quelqu’un d’autre qui travaille sur le même code a tiré une version récente du master juste avant que vous ne le cassiez. Alors tout ce que vous avez à faire est d’aller dans le chat de votre équipe et de demander à cette personne de pousser de force ses changements récents.

Si vous avez de la chance, leur dépôt local aura l’historique complet des commits, votre erreur sera écrasée par du code frais, et rien ne sera perdu. Mais que faire si vous n’avez pas cette chance ? Alors, lisez la suite !

Cas 1 : Vous étiez la dernière personne à pousser vers master avant l’erreur

Bonne nouvelle ! Vous avez tout ce dont vous avez besoin pour défaire votre erreur sous vos yeux. Il suffit de ne pas fermer ou effacer votre terminal. Tout d’abord, allez dans le chat de votre équipe et confessez vos péchés. Demandez aux gens de ne pas s’occuper du repo pendant la prochaine minute pendant que vous réparez les choses.

Dans la sortie de la commande git push --force de votre shell, cherchez une ligne qui ressemble à celle-ci :

 + deadbeef...f00f00ba master -> master (forced update)

Le premier groupe de symboles (qui ressemble au préfixe SHA d’un commit) est la clé du sauvetage. deadbeef est votre dernier bon commit vers la master juste avant que vous n’infligiez des dégâts.

Donc tout ce dont vous avez besoin est de… pousser de force (combattre le feu par le feu !) ce commit vers la branche master, par-dessus un mauvais.

$ git push --force origin deadbeef:master

Congratulations ! Vous avez sauvé la journée. Maintenant il est temps d’apprendre de vos erreurs.

Cas 2 : master a été modifié par quelqu’un d’autre avant que vous ne fassiez des bêtises

Donc, juste avant que vous ne fassiez git push --force quelqu’un avait fermé un tas de pull requests, et le master ne ressemble maintenant en rien à votre copie locale. Vous ne pouvez plus faire git push --force sha1:master car vous n’avez pas de commits récents localement (et vous ne pouvez pas les obtenir avec git fetch car ils n’appartiennent plus à aucune branche). Gardez tout de même votre calme et demandez à vos coéquipiers de ne pas utiliser la télécommande pendant un certain temps.

Nous allons bénéficier du fait que GitHub ne supprime pas immédiatement les commits inaccessibles. Bien sûr, vous ne pouvez pas non plus les récupérer, mais il existe une solution de contournement.

Notez que cela ne fonctionnera que si vous « surveillez » le dépôt, de sorte que tout ce qui s’y passe apparaît dans un flux affiché sur la page d’accueil de votre GitHub. Ouvrez ce flux et cherchez quelque chose comme ceci:

an hour agoUsername pushed to master at org/repo - deadbeef Implement foo - deadf00d Fix bar

Maintenant vous pouvez :

  • Composer une URL https://github.com/org/repo/tree/deadbeef, où deadbeef est un hachage du dernier bon commit de la branche endommagée;
  • Ouvrir le commutateur branches/balises dans l’interface web de GitHub ;

GitHub branch/tag switcher

GitHub branch/tag switcher

  • Créer un nom pour une nouvelle branche temporaire (par ex.g., master-before-force-push);
  • Cliquez sur « Créer une branche ».

Maintenant vous pouvez récupérer tous les commits manquants:

$ git fetchFrom github.com:org/repo * master-before-force-push -> origin/master-before-force-push

Votre problème est maintenant réduit à celui décrit dans un exemple précédent :

$ git push --force origin origin/master-before-force-push:master

Si vous avez toujours besoin que votre travail soit dans le master, il suffit de rebaser par dessus :

$ git rebase origin/master

Comment éviter un tel désastre à l’avenir

  1. GitHub et GitLab ont une fonctionnalité appelée  » branches protégées « . » Marquez master, develop, stable, ou toute autre branche cruciale comme protégée et personne ne sera autorisé à forcer le push dans ces branches. Il est toujours possible de « déprotéger » temporairement une branche si vous avez vraiment besoin d’écraser l’historique.

    Lisez les docs GitHub pour plus de détails.

  2. Au lieu de l’option --force, utilisez --force-with-lease. Elle arrêtera l’opération de push si quelqu’un a poussé sur la même branche pendant que vous travailliez dessus (et n’a pas tiré de modifications).

    Voir cet article d’Atlassian.

  3. Créez des alias pour les commandes qui utilisent git push --force afin d’éviter les actions destructives par accident :

    # ~/.gitconfig deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\""

    Lisez le chapitre de ProGit sur les alias.

  4. Ne faites jamais vos expériences dans la branche principale d’un dépôt ! git checkout -b experiments est votre meilleur ami.

Conseil de pro : git push a de nombreuses options. --force et --all fonctionnent particulièrement bien ensemble. Vous pouvez utiliser ce combo lorsque vous revenez au projet après plusieurs mois d’inactivité. Essayez-le si vous vous sentez très aventureux !

Leave a Reply