Qu’est-ce que Git Rebase et en quoi est-il différent de la fusion?
La fusion et le rebasage atteignent des objectifs similaires, mais les réalisent de différentes manières. Les deux aident à gérer le travail avec les succursales et la collaboration avec plusieurs personnes, mais ils ne sont pas interchangeables, et le rebasage peut être dangereux s’il n’est pas effectué correctement.
Sommaire
Quel est le problème avec le rebasage?
Le rebasage est très compliqué, il est donc important de comprendre comment git
fonctionne sous le capot si nous voulons y donner un sens.
Git stocke votre code sous la forme d’une série de modifications. Vous pouvez penser à cela comme une chaîne, travaillant à l’envers. Chaque édition, ou «commit», fait référence à l’ID du commit précédent et inclut ce qui a changé depuis le commit précédent. Cette chaîne n’est stockée que sur votre ordinateur; votre client Git ne parle à aucun autre client Git sauf s’il effectue un fetch
ou push
(pull
est vraiment juste fetch + merge
avec votre branche locale), et même dans ce cas, il ne parle qu’à un référentiel distant partagé.
Les succursales sont plus compliquées. Git ne stocke qu’une seule chose lorsqu’il s’agit de branches: l’ID du commit à la fin de la branche. De cette façon, vous pouvez les considérer comme la tête de lecture d’un tourne-disque; vous placez la tête de branche à une position spécifique, et elle revient dans la chaîne, «jouant» votre code et arrivant à une version finale. Chaque fois que vous vous engagez, votre client git local déplacera automatiquement la tête de lecture vers le nouveau commit.
Si vous vouliez fusionner la fonctionnalité dans master, vous exécuteriez:
git checkout master git merge feature
Cela crée un nouveau commit de fusion, et s’il y a des conflits, vous devrez les résoudre manuellement. le git merge
La commande déplace la tête de lecture principale vers la nouvelle validation de fusion et supprime la tête de lecture de la fonction, car elle n’est plus nécessaire.
Cette méthode de fusion de code présente trois problèmes:
- Il peut y avoir des modifications sur la branche principale que la branche de fonctionnalité souhaiterait inclure, en particulier si la fonctionnalité prend un certain temps à se développer.
- Être obligé de passer par le processus de fusion chaque fois que vous voulez travailler avec des branches est ennuyeux.
- L’historique des commit est compliqué, bien qu’il s’agisse en grande partie d’un problème esthétique.
Rebasing tente de résoudre ces problèmes, avec plus ou moins de succès. Rebasage des modifications là où vous avez démarré votre branche. La branche entière est soulevée et transportée à la fin de la branche principale actuelle, où elle se connecte à la fin. La branche maître reste intacte et est libre de continuer à recevoir des commits.
Les commits ne sont pas réellement déplacé, cependant, puisque les commits sont immuables. Ils sont plutôt copiés, ce qui entraîne de nouveaux ID de validation. Les commits précédents restent bloqués, se cachant dans vos fichiers Git mais ne seront jamais revus, car la tête de lecture a été déplacée ailleurs.
Pour exécuter ce processus à partir de la ligne de commande, vous exécuteriez:
git checkout feature git pull git rebase master
Cela ouvre la branche, extrait les modifications actuelles vers le maître, puis rebase la branche de fonctionnalité sur la branche maître.
À ce stade, le code de la branche des fonctionnalités est désormais plus à jour, ce qui est la seule réelle fonctionnalité de git rebase
. Le rebasage ne fusionne pas les branches, car il ne crée aucune validation de fusion ni ne déplace la tête de lecture du maître.
Si vous souhaitez fusionner après le rebasage, vous exécutez:
git checkout master git merge feature
Ce qui ressemblerait à ceci, avec la tête de lecture du maître remplaçant la tête de lecture de fonction:
Le rebasage ne résout donc pas le problème du traitement des fusions, car vous devrez de toute façon fusionner à la fin pour mettre à jour la branche principale. L’actuel merge
La commande à la fin devrait cependant se dérouler sans accroc, car le processus de rebasage vous oblige à «fusionner» les modifications, ce qui peut encore provoquer des conflits. Et si vous souhaitez continuer à travailler sur votre branche, vous devez toujours «fusionner» les modifications.
Ne pas rebaser les branches partagées
Rappelez-vous comment le rebasage des copies commet et laisse une tête de lecture bloquée? C’est en fait un problème majeur si vous travaillez avec du code partagé. Supposons que vous ayez créé la branche de fonctionnalités et que vous la transmettiez à votre dépôt afin que vos collègues puissent la tester. C’est tout à fait correct, mais si l’un d’eux voulait bifurquer de votre branche, lorsque vous avez finalement rebasé, vous vous retrouvez avec ceci:
La branche feature2 de votre collègue fait désormais référence à une ancienne chaîne de commits. Votre client Git n’a aucun moyen de le savoir, puisque la branche feature2 est stockée sur l’ordinateur de votre collègue. Ils n’ont également aucun moyen de savoir que vous avez rebasé jusqu’à ce que vous poussiez vos changements.
Lorsque vous avez rebasé, il n’a pas copié la branche feature2 lorsqu’il a copié tous les commits. Même si cela pouvait, cela n’affecterait pas le dépôt Git local de votre collègue, ce qui désynchroniserait tout. La solution ici serait de rebaser feature2 sur la fonctionnalité à l’endroit où elle se trouverait, mais c’est compliqué, même selon les normes Git, et ce n’est qu’un exemple très simple.
En bout de ligne, ne rebasez pas si vous ne travaillez pas localement.
Quand est-il préférable de rebaser plutôt que de fusionner?
Si votre branche prend un certain temps à se développer, le rebasage résout le problème du «syndrome de branche», où votre code est bien trop obsolète avec le maître de travail, et vous devez le mettre à jour pour continuer à travailler. En général, vous devriez essayer d’éviter ce problème autant que possible, mais le rebasage peut le résoudre quand il se produit.
Si vous ne faites que de petits changements quotidiens incrémentiels, vous devez plutôt travailler sur une branche principale locale et utiliser des demandes d’extraction lorsque vous êtes prêt à appliquer vos modifications. Ceux-ci utilisent le modèle des branches topiques, créé spécifiquement pour stocker votre code avant qu’il ne soit approuvé pour une fusion.
Mais, si vous travaillez sur une période hebdomadaire et que vous allez finir par faire plusieurs pull requests et fusionner plusieurs fois, vous pouvez travailler sur votre code un peu plus longtemps, rebaser localement pour les mises à jour et effectuer une pull request au fin pour réduire la quantité de tests et de parler aux superviseurs. Le rebasage est principalement une chose locale, vous pouvez donc le faire sur vos succursales de préparation sans attendre l’approbation.
Si personne d’autre ne dépend de votre succursale, vous pouvez rebase avant une fusion de branche pour rendre l’historique de validation propre et unidimensionnel. Cependant, on pourrait soutenir que la fusion traditionnelle, bien que certainement plus laide, est plus facile à suivre et à déboguer, car les validations de fusion sont entièrement non destructives. Dans tous les cas, le rebasage doit être effectué juste avant la fusion de vos modifications, sinon vous risquez de rencontrer le problème de la mise à jour de Master avant que vos modifications ne soient approuvées.