Un guide pour réparer les erreurs avec Git (Partie 2)

Publié: 2022-03-10
Résumé rapide ↬ Erreurs. Ces méchants cruels ne s'arrêtent même pas au beau monde du développement logiciel. Mais même si nous ne pouvons pas éviter de faire des erreurs, nous pouvons apprendre à les défaire ! Cet article vous montrera les bons outils pour votre travail quotidien avec Git. Vous voudrez peut-être également consulter le premier article de la série.

Dans cette deuxième partie de notre série sur "Réparer les erreurs avec Git", nous regarderons à nouveau courageusement le danger dans les yeux : j'ai préparé quatre nouveaux scénarios apocalyptiques, y compris, bien sûr, des moyens astucieux de nous sauver la peau ! Mais avant de plonger : jetez un œil aux articles précédents sur Git pour encore plus de méthodes d'auto-sauvetage qui vous aideront à réparer vos erreurs avec Git !

Allons-y!

Récupérer une branche supprimée à l'aide du Reflog

Avez-vous déjà supprimé une branche et, peu de temps après, réalisé que vous n'auriez pas dû ? Dans le cas improbable où vous ne connaissez pas ce sentiment, je peux vous dire que ce n'est pas bon. Un mélange de tristesse et de colère monte en vous, alors que vous pensez à tout le travail acharné qui a été consacré aux commits de cette branche, à tout le code précieux que vous avez maintenant perdu.

Heureusement, il existe un moyen de ramener cette branche d'entre les morts - avec l'aide d'un outil Git nommé "Reflog". Nous avions utilisé cet outil dans la première partie de notre série, mais voici un petit rappel : le Reflog est comme un journal où Git note chaque mouvement du pointeur HEAD dans votre dépôt local. En d'autres termes, moins ringards : chaque fois que vous passez à la caisse, validez, fusionnez, rebasez, sélectionnez, etc., une entrée de journal est créée. Cela fait du Reflog un filet de sécurité parfait lorsque les choses tournent mal !

Prenons un exemple concret :

 $ git branch * feature/login master

Nous pouvons voir que nous avons actuellement extrait notre feature/login branche. Disons que c'est la branche que nous allons supprimer (par inadvertance). Avant de pouvoir le faire, cependant, nous devons passer à une autre branche car nous ne pouvons pas supprimer notre branche HEAD actuelle !

 $ git checkout master $ git branch -d feature/login

Notre précieuse branche de fonctionnalités a maintenant disparu - et je vous accorderai une minute pour (a) comprendre la gravité de notre erreur et (b) pleurer un peu. Après que vous ayez essuyé les larmes, nous devons trouver un moyen de ramener cette branche ! Ouvrons le Reflog (en tapant simplement git reflog ) et voyons ce qu'il nous réserve :

Les protocoles Reflog de Git consignent toutes les actions majeures dans notre dépôt local
Les protocoles Reflog de Git consignent toutes les actions majeures dans notre référentiel local. ( Grand aperçu )

Voici quelques commentaires pour vous aider à donner un sens à la sortie :

  • Tout d'abord, il faut savoir que le Reflog trie ses entrées par ordre chronologique : les éléments les plus récents sont en tête de liste.
  • L'élément le plus haut (et donc le plus récent) est la git checkout que nous avons exécutée avant de supprimer la branche. Il est enregistré ici dans le Reflog parce que c'est l'un de ces "mouvements du pointeur HEAD" que le Reflog enregistre si consciencieusement.
  • Pour réparer notre grave erreur, nous pouvons simplement revenir à l'état d' avant - qui est également proprement et clairement enregistré dans le Reflog !

Essayons donc ceci, en créant une nouvelle branche (avec le nom de notre branche "perdue") qui commence à cet état "avant" du hachage SHA-1 :

 $ git branch feature/login 776f8ca

Et voila ! Vous serez ravi de voir que nous avons maintenant restauré notre branche apparemment perdue !

Si vous utilisez une interface graphique de bureau Git telle que "Tower", vous pouvez prendre un joli raccourci : appuyez simplement sur CMD + Z sur votre clavier pour annuler la dernière commande - même si vous venez de supprimer violemment une branche !

Une interface graphique de bureau telle que Tower peut faciliter le processus d'annulation des erreurs.
Plus après saut! Continuez à lire ci-dessous ↓

Déplacer un commit vers une autre branche

Dans de nombreuses équipes, il existe un accord pour ne pas s'engager sur des branches de longue durée comme main ou develop : des branches comme celles -ci ne devraient recevoir de nouveaux commits que par le biais d'intégrations (par exemple, fusions ou rebases). Et pourtant, bien sûr, les erreurs sont inévitables : on oublie parfois et on commet quand même sur ces branches ! Alors, comment pouvons-nous nettoyer le gâchis que nous avons créé ?

Déplacer un commit vers sa branche de destination correcte
Notre commit a atterri sur la mauvaise branche. Comment pouvons-nous le déplacer vers sa branche de destination correcte ? ( Grand aperçu )

Heureusement, ces types de problèmes peuvent être facilement corrigés. Retroussons nos manches et mettons-nous au travail.

La première étape consiste à basculer vers la bonne branche de destination, puis à déplacer le commit en utilisant la commande cherry-pick :

 $ git checkout feature/login $ git cherry-pick 776f8caf

Vous aurez maintenant le commit sur la branche souhaitée, là où il aurait dû se trouver en premier lieu. Impressionnant!

Mais il reste encore une chose à faire : nous devons nettoyer la branche où elle a atterri accidentellement en premier ! La commande cherry-pick , pour ainsi dire, a créé une copie du commit — mais l'original est toujours présent sur notre branche de longue date :

Une copie du commit sur la bonne branche, mais l'original s'affiche toujours sur la mauvaise branche
Nous avons réussi à créer une copie du commit sur la bonne branche, mais l'original est toujours là — sur la mauvaise branche. ( Grand aperçu )

Cela signifie que nous devons revenir à notre branche de longue date et utiliser git reset pour la supprimer :

 $ git checkout main $ git reset --hard HEAD~1

Comme vous pouvez le voir, nous utilisons ici la commande git reset pour effacer le commit défectueux. Le paramètre HEAD~1 indique à Git de "revenir 1 révision derrière HEAD", effaçant ainsi le commit le plus élevé (et dans notre cas : indésirable) de l'historique de cette branche.

Et voilà : le commit est maintenant là où il aurait dû être en premier lieu et notre branche de longue date est propre — comme si notre erreur ne s'était jamais produite !

Modification du message d'un ancien commit

Il est trop facile d'introduire une faute de frappe dans un message de validation et de ne la découvrir que bien plus tard. Dans un tel cas, la bonne vieille option --amend de git commit ne peut pas être utilisée pour résoudre ce problème, car elle ne fonctionne que pour le tout dernier commit. Pour corriger tout commit plus ancien que cela, nous devons recourir à un outil Git appelé "Interactive Rebase".

Un message de commit qui mérite d'être changé
Voici un message de validation qui mérite d'être modifié. ( Grand aperçu )

Tout d'abord, nous devons indiquer à Interactive Rebase quelle partie de l'historique des commits nous voulons modifier. Cela se fait en lui alimentant un hash de commit : le commit parent de celui que nous voulons manipuler.

 $ git rebase -i 6bcf266b

Une fenêtre d'édition s'ouvrira alors. Il contient une liste de tous les commits après celui que nous avons fourni comme base pour le rebase interactif dans la commande :

Affichage de la gamme de commits que nous avons sélectionnés pour l'édition dans notre session Interactive Rebase
La gamme de commits que nous avons sélectionnés pour l'édition dans notre session Interactive Rebase. ( Grand aperçu )

Ici, il est important que vous ne suiviez pas votre première impulsion : dans cette étape, nous n'éditons pas encore le message de validation. Au lieu de cela, nous disons seulement à Git quel type de manipulation nous voulons faire avec quel(s) commit(s). Très commodément, il y a une liste de mots-clés d'action notés dans les commentaires au bas de cette fenêtre. Dans notre cas, nous marquons la ligne #1 avec reword (remplaçant ainsi le pick standard).

Tout ce qui reste à faire dans cette étape est d'enregistrer et de fermer la fenêtre de l'éditeur. En retour, une nouvelle fenêtre d'éditeur s'ouvrira contenant le message actuel du commit que nous avons marqué. Et c'est enfin le moment de faire nos montages !

Voici tout le processus en un coup d'œil pour vous :

Utiliser Interactive Rebase pour modifier le message d'un ancien commit, du début à la fin.

Corriger un commit cassé (d'une manière très élégante)

Enfin, nous allons jeter un œil à fixup , le couteau suisse des outils d'annulation. En termes simples, cela vous permet de corriger un commit cassé/incomplet/incorrect après coup. C'est vraiment un outil merveilleux pour deux raisons :

  1. Peu importe quel est le problème.
    Vous avez peut-être oublié d'ajouter un fichier, supprimé quelque chose, effectué une modification incorrecte ou simplement une faute de frappe. fixup fonctionne dans toutes ces situations!
  2. C'est extrêmement élégant.
    Notre réaction normale et instinctive face à un bogue dans un commit est de produire un nouveau commit qui résout le problème. Cette façon de travailler, aussi intuitive qu'elle puisse paraître, rend votre historique de commit très chaotique, très bientôt. Vous avez des commits "d'origine", puis ces petits commits "de pansement" qui corrigent les problèmes qui se sont produits dans les commits d'origine. Votre historique est jonché de petits commits de pansement dénués de sens, ce qui rend difficile la compréhension de ce qui s'est passé dans votre base de code.
Votre historique de commits peut être très difficile à lire si vous corrigez constamment de petites erreurs avec des commits dits de pansement
Corriger constamment de petites erreurs avec des "commits de pansement" rend votre historique de commit très difficile à lire. ( Grand aperçu )

C'est là que fixup entre en jeu. Elle vous permet de toujours faire ce commit de pansement correctif. Mais voici la magie : il l'applique ensuite au commit original et cassé (en le réparant de cette façon), puis supprime complètement le vilain commit de pansement !

Fixup applique vos corrections au commit d'origine, puis supprime le commit de pansement superflu
Fixup applique vos corrections au commit d'origine, puis supprime le commit de pansement superflu. ( Grand aperçu )

Nous pouvons passer par un exemple pratique ensemble ! Disons que le commit sélectionné ici est cassé.

Corriger le commit incorrect sélectionné de manière élégante
Le commit sélectionné est incorrect — et nous allons le corriger de manière élégante. ( Grand aperçu )

Disons également que j'ai préparé des modifications dans un fichier nommé error.html qui résoudra le problème. Voici la première étape que nous devons faire :

 $ git add error.html $ git commit --fixup 2b504bee

Nous créons un nouveau commit, mais nous disons à Git qu'il s'agit d'un commit spécial : c'est un correctif pour un ancien commit avec le hachage SHA-1 spécifié ( 2b504bee dans ce cas).

La deuxième étape consiste maintenant à démarrer une session Interactive Rebase, car la fixup appartient au grand ensemble d'outils d'Interactive Rebase.

 $ git rebase -i --autosquash 0023cddd

Deux choses méritent d'être expliquées à propos de cette commande. Tout d'abord, pourquoi ai-je fourni 0023cddd comme hachage de révision ici ? Parce que nous devons démarrer notre session Interactive Rebase au niveau du commit parent de notre compagnon brisé.

Deuxièmement, à quoi sert l'option --autosquash ? Cela nous enlève beaucoup de travail ! Dans la fenêtre de l'éditeur qui s'ouvre maintenant, tout est déjà préparé pour nous :

La fenêtre de la session Interactive Rebase
La fenêtre de session Interactive Rebase ( Grand aperçu )

Grâce à l'option --autosquash , Git a déjà fait le gros du travail pour nous :

  1. Il a marqué notre petit commit de pansement avec le mot-clé d'action de fixup . De cette façon, Git le combinera avec le commit directement au- dessus , puis le supprimera.
  2. Il a également réorganisé les lignes en conséquence, déplaçant notre commit de pansement directement sous le commit que nous voulons corriger (encore une fois : le fixup fonctionne en combinant le commit balisé avec celui ci- dessus !).

En bref : Il n'y a rien à faire pour nous que de fermer la fenêtre !

Jetons un dernier regard sur le résultat final.

  • Le commit précédemment cassé est corrigé : il contient désormais les modifications que nous avons préparées dans notre commit de pansement.
  • L'affreux commit de pansement lui-même a été abandonné : l'historique des commits est clair et facile à lire, comme si aucune erreur ne s'était produite.
Un exemple de ce à quoi ressemble un historique de validation propre
Le résultat final après l'utilisation de l'outil de correction : un historique de validation propre ! ( Grand aperçu )

Savoir réparer les erreurs est un super pouvoir

Toutes nos félicitations! Vous êtes maintenant capable de sauver votre peau dans de nombreuses situations difficiles ! Nous ne pouvons pas vraiment éviter ces situations : quelle que soit notre expérience en tant que développeurs, les erreurs font tout simplement partie du travail. Mais maintenant que vous savez comment les gérer, vous pouvez les affronter avec un rythme cardiaque décontracté.

Si vous voulez en savoir plus sur la correction des erreurs avec Git, je peux vous recommander le "Kit de premiers secours pour Git" gratuit, une série de courtes vidéos sur exactement ce sujet.

Amusez-vous à faire des erreurs et, bien sûr, à les défaire facilement !