Agilité

git et la face cachée du Rebase

Déc 22, 2023

Jonathan EVAIN

« Faire une rebase ? *sight* heu… ok… »

Jean-Michel Fullstack – Développeur fébrile

Jean-Michel est inquiet. En effet, lorsque nous collaborons à plusieurs sur un projet, quelque soit les technologies utilisées, il est important de garder à l’esprit que notre travail impactera inévitablement les travaux de nos collègues.

« Merci Captain Obvious ! »

Jean-Michel Fullstack – Développeur irritable

C’est pourquoi des contrôleurs de code source sont largement répandus dans les équipes de développement ; L’équipe de Jean-Michel, utilise git, le plus populaire d’entre eux, il est simple à appréhender et propose nombre de fonctionnalités pour collaborer efficacement.

Pour autant, il réside encore aujourd’hui certaines incompréhensions quant aux mécaniques basiques de git, conduisant inévitablement à des erreurs, un alourdissement de la collaboration et de la frustration chez Jean-Michel. Le Rebase, commande largement utilisée dans différents workflow, est un des points de souffrance qui réside encore aujourd’hui et taille une mauvaise réputation à git.

Faire un Rebase – rien de plus simple Jean-Mich’

« Tout de suite les familiarités ! »

Jean-Michel Fullstack – Développeur susceptible

Contexte :

Il est important de garder sa branche de travail à jour par rapport à la branche commune pour éviter que la première soit trop éloignée de la seconde. Il faut alors comprendre ce qu’est le rebase, ce qu’il implique et surtout ce qui se cache derrière cette opération.

Afin de faciliter la compréhension des explications à venir, convenons d’abord d’une règle de nommage :

    • develop : C’est la branche commune contenant le code source implémenté par tous les collaborateurs. Elle sert de référence des travaux en cours.
    • feature : La branche de travail. Elle peut exister en autant d’exemplaire qu’il y a de travaux à effectuer et est issue de la branche develop. Elle sera rapatriée vers celle-ci une fois l’implémentation terminée.
Nous partirons du principe que les branches précitées disposent d’un équivalent sur le serveur git distant.

Faire un Rebase

    1. On se positionne sur la branche develop : git checkout develop
    2. On récupère la dernière version de la branche develop en local : git pull --rebase
    3. On se replace sur notre branche feature : git checkout <nom_de_ma_branche_feature>
    4. On fait pointer la branche feature sur le dernier commit de develop : git rebase develop

En détail, le rebase va :

    1. Mettre de côté tous les commits effectués sur la branche feature depuis sa création (ou depuis le dernier rebase)
    2. Réinitialiser la branche feature avec la version la plus récente de la branche develop.
    3. Tenter de fusionner un à un tous les commits précédemment mis de côté sur la branche feature.

Cette action réécrit l’historique de notre branche feature.
En effet, lors de sa création, la branche feature a été tirée à partir d’un ancien commit de la branche develop.
Mais la branche develop à poursuivit son chemin, accueillant de nouveau commits ; des modifications qu’il convient de récupérer sur la branche feature.
Le rebase va donc modifier l’origine de la branche feature (ancien commit sur develop) en la raccordant au commit le plus récent de la branche develop.

« Ah ben je savais pas ça ! »

Jean-Michel Fullstack – Développeur qui savait pas ça et qui sait maintenant

Résolution des conflits (calme-toi Jean-Mi, tout va bien se passer)

« Je suis parfaitement calme ! »

Jean-Michel Fullstack – Développeur pas calme du tout

Lors d’un rebase, des conflits peuvent survenir à chaque tentative de merge (et c’est normal Jeannot). git nous laisse alors la main pour résoudre le ou les conflits remontés sur chaque merge de commit.

Une fois le(s) conflit(s) résolu(s) :

    1. On ajoute le(s) fichier(s) modifiés aux tracker : git add <monFichierOuYaPlusDeConflit><.><-all> 
    2. Et on continue le rebase : git rebase –continue
A ce stade git passe au commit suivant et l’opération se répète jusqu’à ce que tous les commits soient fusionnés.

Le piège du rebase

Une fois le rebase terminé, Nous pouvons tranquillement pousser la branche feature vers le repository distant…

ERREUR JEAN-MICHEL !

« Fichtre, Diantre ! »

Jean-Michel Fullstack – Développeur outré et moyenâgeux

Reprenons : le rebase a fait autant de merge que de commits mis de côté.

Il a fait des merges !

Rappelons qu’un merge équivaut à un commit de merge (sur la branche feature en l’occurrence). Résultat, la branche feature fraichement rebase dispose de nouveaux commits à pousser vers le Repo distant. Cependant, notre branche feature distante est sur une version bien différente de notre branche de feature local, elles ont divergé. Il est alors impossible de pousser nos commits sans tirer la version distante, Ce que git nous invite à faire… …Et c’est ce qu’il ne faut pas faire !

« git, vil coquin ! »

Jean-Michel Fullstack – Développeur fan de Molière

Pour comprendre, cela il faut s’intéresser à cette divergence

Lors du rebasegit à mit nos commits locaux de côté pour les fusionner par la suite, en créant de nouveaux commits. Pour autant, ces commits peuvent déjà être présent sur la branche feature distante, mais avec une histoire et un hash (un ID) différents.
Cependant, nous n’avons plus ces commits en local (souviens-toi Jean-Jean de l’étape 2 du mécanisme du rebase) d’où la nécessité celons git de tirer la branche distante.

Mais si nous faisons cela, nous allons nous retrouver avec tous les commits de la branche distante que nous avions « perdu » lors du rebase et une copie conforme de ceux que nous avions mis de côté lors du rebase (même contenu, hash différent), nous retrouvant ainsi avec une branche de travail local pleine de doublons… … Que git nous invite à pousser vers le repository distant (Celui la alors !)

« Mais comment passer outre cette obligation et mettre à jour notre branche de travail distante une bonne fois pour toute ? »

Jean-Michel Fullstack – Développeur impatient

Bonne question Jean-Michel (pas du tout scriptée en plus) ! Une solution consiste à forcer la mise à jour de notre branche distante (ou écraser son contenu) avec la branche local

git push --force

Ainsi notre branche distante dispose de la dernière version de develop + les travaux entamés en local, prête à faire l’objet d’une Pull Request.

« J’ai tout compris ! Je me sens rassuré ! »

Jean-Michel Fullstack – Développeur qui à tout compris et qui se sent rassuré

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Découvrez nos autres articles

Aller au contenu principal