Git, en toute simplicité : modifier l’historique avec rebase — partie II
Or Kamara
17 juin 2020
0 minutes de lectureRavi de vous retrouver pour la deuxième partie de notre guide pour travailler avec Git en toute simplicité !
Dans l’article précédent, nous avons vu les bases de Rebase ainsi que deux cas courants que nous pouvons rencontrer lorsque nous travaillons avec Git. Vous trouverez la première partie ici. Nous allons maintenant aborder quatre autres cas courants et tirer quelques conclusions.
C’est parti !
Cas courants (et comment les gérer !) — partie II
Reprenons là où nous en étions la dernière fois avec quelques cas courants où vous pourriez vouloir modifier l’historique de votre code, et voyons comment procéder avec Git :
1. Scinder un ancien commit en deux (edit)
Imaginons que vous veniez de vous rendre compte que vous avez fait une erreur en fusionnant deux commits (voir la partie I pour plus de détails) et que vous souhaitiez annuler le squash de 17a73c1 dans e2952e7, afin que le nouveau fichier soit placé dans un commit distinct. Pour cela, exécutez tous les commits jusqu’au point à modifier, arrêtez-vous, effectuez les changements, puis continuez. Autrement dit, utilisez l’option edit.
Commençons par relancer git rebase -i master, mais cette fois avec l’option edit sur le commit à scinder (le deuxième commit, `6871683`) :
Après avoir quitté l’écran de rebase, voici ce qui s’affiche :
Git a donc exécuté les premier et deuxième commits, puis s’est arrêté : à nous de jouer. Nous pouvons apporter tous les changements souhaités !
Voici à quoi ressemble actuellement notre graphe Git :
Comme indiqué précédemment, nous voulons scinder le deuxième commit en deux commits distincts, un par fichier. Pour commencer, réinitialisons les modifications du deuxième commit en exécutant git reset --soft HEAD^. La commande reset modifie le commit vers lequel pointe actuellement la branche HEAD. Avec l’option --soft, l’index et le répertoire de travail sont conservés, tandis que tous les fichiers modifiés entre le HEAD d’origine et le commit sont placés dans la zone de préparation.
Voici le nouveau statut Git. Comme vous pouvez le voir, les deux fichiers sont en attente :
Retirons maintenant b2.txt de la liste des fichiers indexés en exécutant git restore --staged b2.txt :
Avec seulement b.txt comme fichier indexé, nous pouvons maintenant créer le premier commit correspondant à la première partie du deuxième commit. Ensuite, indexons b2.txt et créons le deuxième commit :
Notre graphe Git ressemble maintenant à ceci :
Il ne reste plus qu’à poursuivre le rebase et à exécuter les commits suivants en lançant
git rebase --continue. Le graphe Git final devrait ressembler à ceci :
2. Modifier tous les fichiers d’un commit spécifique (edit)
Le scénario suivant vous est probablement familier : vous avez envoyé tout votre code, parfaitement réparti en plusieurs commits, puis vous vous rendez compte que vous avez oublié de lancer le linter. Comme nous l’avons expliqué, la solution n’est pas de créer un autre commit nommé fix linting, mais de corriger le linting dans chaque commit.
S’il s’agit d’une modification mineure, nous pouvons utiliser l’option squash. Mais si plusieurs changements concernent plusieurs commits, mieux vaut exécuter notre script de linting un par un sur chaque commit (ou sur les commits à corriger). Pour cela, nous pouvons à nouveau utiliser l’option edit (comme dans l’exemple précédent).
Relançons git commit rebase -i en utilisant l’option edit sur le premier commit (qui comprend plusieurs fichiers) :
Comme précédemment, Git s’arrête après avoir exécuté le premier commit :
Nous pouvons maintenant lancer notre linter (par exemple, npm run lint) et vérifier l’état de notre dépôt :
Comme vous pouvez le voir, le script du linter a modifié le contenu de 6 fichiers (a*.txt). Il ne reste plus qu’à intégrer les modifications actuelles en les indexant et en créant un commit, puis à poursuivre le rebase :
Et voici à quoi devrait ressembler le graphe Git :
3. Vérifier que les tests passent pour chaque commit (exec)
Lorsque vous répartissez votre code en plusieurs commits, gardez à l’esprit que chacun doit pouvoir fonctionner de manière autonome. Autrement dit, après avoir fusionné plusieurs commits dans l’une des branches principales, vous devez pouvoir revenir à chacun d’eux et vous attendre à ce que le code compile et que tous les tests passent.
Comment vérifier tout cela avant de fusionner les commits ?
Lançons manuellement tous les tests sur chaque commit ! Je plaisante, bien sûr : nous devrions automatiser cette tâche :) Pour cela, nous pouvons utiliser l’option exec.
Cette option nous permet d’exécuter des scripts shell dans le cadre du processus de rebase. Il suffit d’ajouter de nouvelles lignes avec la commande exec aux endroits souhaités. Par exemple, relançons git rebase -i master :
Passons maintenant à la partie amusante : lancer les tests (en exécutant le script ./run_tests.sh) après chaque commit :
Voici le résultat affiché lorsque vous quittez l’écran de rebase :
Comme vous pouvez le voir, Git a exécuté le script de test après chaque commit. Nous savons donc que le commit feat: 2nd commit contient un élément qui fait échouer les tests. Il est également possible d’ajouter une seule commande exec après chaque commit en exécutant :
$ git rebase -i --exec "./run_tests.sh"
Dernière chose à savoir (ou plutôt première) : comment annuler
Ce n’est pas vraiment un scénario, mais plutôt un avertissement : la commande rebase peut être dangereuse !Si vous l’utilisez sans comprendre les effets des commandes, vous risquez de perdre votre travail. C’est pourquoi je vais commencer par deux recommandations :
Avant de modifier les commits, assurez-vous toujours d’avoir une sauvegarde fiable de votre dépôt Git. Pour ma part, le plus simple est d’envoyer toutes mes modifications vers une branche distante. En cas de problème, je peux toujours revenir à mon code d’origine (avec
git reset).Assurez-vous de bien comprendre les commandes. Avant de les utiliser pour la première fois sur votre code, testez-les dans un dépôt Git temporaire.
N’oubliez pas que vous pouvez toujours interrompre le processus de rebase et revenir à l’état initial :
Sur l’écran initial du rebase, supprimez simplement toutes les lignes de commits : rien ne changera.
Au milieu du processus de rebase, si vous êtes perdu pour une raison quelconque et ne savez pas quoi faire, vous pouvez toujours exécuter
git rebase --abort. Cette commande interrompt le rebase et rétablit l’état d’origine de votre dépôt (avant l’exécution degit rebase -i).
Pour résumer
Comme nous l’avons vu dans les derniers exemples, git rebase est une commande puissante, en particulier en mode interactif. Elle peut servir dans une infinité de situations, mais j’espère vous avoir donné les bases pour comprendre quand chaque option est utile.
Ce que j’aimerais surtout que vous reteniez de cet article, c’est qu’il faut utiliser git rebase avec discernement et sans crainte. Je sais que les débuts peuvent être un peu intimidants et que vous aimeriez peut-être avoir quelqu’un à vos côtés au moment d’appuyer sur Entrée, mais c’est tout à fait normal. Avec un peu de pratique, cela deviendra une habitude. Et je suis sûr qu’il existe bien d’autres scénarios, propres à vos cas d’usage, où cette commande peut vous être utile.
Amusez-vous bien !
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.



