web-dev-qa-db-fra.com

Pourquoi git pull effectue-t-il une fusion au lieu d'un rebase par défaut?

Considérez la situation suivante:

  • Vous avez un clone d'un référentiel git
  • Vous avez des commits locaux (commits qui n'ont pas encore été poussés n'importe où)
  • Le référentiel distant contient de nouvelles validations que vous n'avez pas encore rapprochées

Donc quelque chose comme ça:

Unmerged commits

Si vous exécutez git pull avec les paramètres par défaut, vous obtiendrez quelque chose comme ceci:

merge commit

En effet, git a effectué une fusion.

Il existe cependant une alternative. Vous pouvez demander à pull de faire un rebase à la place:

git pull --rebase

et vous obtiendrez ceci:

rebased

À mon avis, la version rebasée présente de nombreux avantages qui consistent principalement à garder votre code et l'historique propres, donc je suis un peu frappé par le fait que git effectue la fusion par défaut. Oui, les hachages de vos commits locaux seront modifiés, mais cela semble être un petit prix à payer pour l'historique plus simple que vous obtenez en retour.

En aucun cas, je ne suggère que ce soit en quelque sorte un mauvais ou un mauvais défaut. J'ai juste du mal à penser aux raisons pour lesquelles la fusion pourrait être préférée par défaut. Avons-nous une idée de la raison pour laquelle il a été choisi? Existe-t-il des avantages qui le rendent plus adapté par défaut?

La principale motivation de cette question est que mon entreprise essaie d'établir des normes de base (je l'espère, plus comme des directives) pour la façon dont nous organisons et gérons nos référentiels afin de faciliter pour les développeurs l'approche d'un référentiel avec lequel ils n'ont pas travaillé auparavant. Je suis intéressé à faire valoir que nous devrions généralement rebaser dans ce type de situation (et probablement pour recommander aux développeurs de définir leur configuration globale pour rebaser par défaut), mais si je m'y opposais, je demanderais certainement pourquoi le rebase n'est pas '' t par défaut si c'est génial. Je me demande donc s'il manque quelque chose.

Il a été suggéré que cette question soit un double de Pourquoi tant de sites Web préfèrent-ils "git rebase" à "git merge"? ; cependant, cette question est quelque peu l'inverse de celui-ci. Il examine les avantages de la fusion par rapport à la fusion, tandis que cette question porte sur les avantages de la fusion par rapport à la fusion. Les réponses reflètent cela, en se concentrant sur les problèmes de fusion et les avantages du rebase.

71
jpmc26

Il est difficile de savoir avec certitude pourquoi la fusion est le défaut sans avoir entendu la personne qui a pris cette décision.

Voici une théorie ...

Git ne peut pas présumer qu'il est correct de --base chaque tirage. Écoutez comment ça sonne. "Rebase chaque tirage." sonne juste mal si vous utilisez des demandes de tirage ou similaires. Souhaitez-vous rebaser sur une demande de tirage?

Dans une équipe qui n'utilise pas seulement Git pour le contrôle de source centralisé ...

  • Vous pouvez tirer de l'amont et de l'aval. Certaines personnes tirent beaucoup de l'aval, des contributeurs, etc.

  • Vous pouvez travailler sur des fonctionnalités en étroite collaboration avec d'autres développeurs, en les extrayant ou à partir d'une branche de sujet partagée et en les mettant parfois à jour en amont. Si vous rebassez toujours, vous finissez par changer l'historique partagé, sans parler des cycles de conflit amusants.

Git a été conçu pour une grande équipe hautement distribuée où tout le monde ne tire pas et ne pousse pas vers un seul dépôt central. La valeur par défaut est donc logique.

  • Les développeurs qui ne savent pas quand il est possible de rebaser fusionneront par défaut.
  • Les développeurs peuvent rebaser quand ils le souhaitent.
  • Les commissaires qui font beaucoup de tirages et qui ont beaucoup de tirages obtiennent la valeur par défaut qui leur convient le mieux.

Pour preuve d'intention, voici un lien vers un e-mail bien connu de Linus Torvalds avec ses vues sur le moment où ils ne devraient pas rebaser. Dri-devel git pull email

Si vous suivez le fil entier, vous pouvez voir qu'un développeur tire d'un autre développeur et Linus tire des deux. Il rend son opinion assez claire. Puisqu'il a probablement décidé des valeurs par défaut de Git, cela pourrait expliquer pourquoi.

Beaucoup de gens utilisent maintenant Git de manière centralisée, où tout le monde dans une petite équipe ne tire qu'à partir d'un référentiel central en amont et pousse vers cette même télécommande. Ce scénario évite certaines situations où un rebasage n'est pas bon, mais ne les élimine généralement pas.

Suggestion: Ne faites pas de politique de modification de la valeur par défaut. Chaque fois que vous associez Git à un grand groupe de développeurs, certains développeurs ne comprendront pas Git très profondément (moi y compris). Ils iront à Google, SO, obtiendront des conseils de livre de cuisine et se demanderont ensuite pourquoi certaines choses ne fonctionnent pas, par exemple pourquoi git checkout --ours <path> obtenir la mauvaise version du fichier? Vous pouvez toujours réviser votre environnement local, créer des alias, etc. selon vos goûts.

56
joshp

Si vous lisez la page de manuel git pour rebase, il dit :

Rebaptiser (ou toute autre forme de réécriture) une branche sur laquelle d'autres ont basé leur travail est une mauvaise idée: toute personne en aval est obligée de corriger manuellement son historique. Cette section explique comment effectuer la correction du point de vue en aval. La vraie solution, cependant, serait d'éviter en premier lieu de rebaser l'amont.

Je pense que cela le dit assez bien comme raison de ne pas utiliser du tout rebase, et encore moins de le faire automatiquement pour chaque tirage. Certaines personnes considèrent le rebase est dangereux . Peut-être que cela n'aurait jamais dû être mis en git, car tout ce qu'il semble faire, c'est embellir l'histoire, ce qui ne devrait pas être nécessaire dans tout SCM dont le seul travail essentiel est de préserver l'histoire.

Quand vous dites "garder ... l'histoire propre", pensez que vous vous trompez. Cela peut sembler plus joli, mais pour un outil conçu pour conserver l'historique des révisions, il est beaucoup plus propre de conserver chaque commit afin que vous puissiez voir ce qui s'est passé. Désinfecter l'histoire par la suite, c'est comme polir la patine, faire une riche antiquité comme une repro brillante :-)

15
gbjbaanb

Vous avez raison, en supposant que vous n'avez qu'un seul référentiel local/modifié. Cependant, pensez par exemple à l'existence d'un deuxième PC local.

Une fois que votre copie locale/modifiée est poussée ailleurs, le rebasage va visser ces copies. Bien sûr, vous pourriez forcer à pousser, mais cela devient rapidement compliqué. Que se passe-t-il si un ou plusieurs d'entre eux ont un autre commit complètement nouveau?

Comme vous pouvez le voir, c'est très situationnel, mais la stratégie de base me semble (beaucoup) plus pratique dans les cas non spéciaux/collaboratifs.


Deuxième différence: la stratégie de fusion conservera une structure claire et cohérente dans le temps. Après les rebases, il est très probable que les commits plus anciens suivent des changements plus récents, rendant l'histoire et son flux plus difficiles à comprendre.

12
Mario

La grande raison est probablement que le comportement par défaut devrait "simplement fonctionner" dans les dépôts publics. Retrouver l'histoire que d'autres personnes ont déjà fusionnée va leur causer des ennuis. Je sais que vous parlez de votre repo privé, mais en général, git ne sait pas ou ne se soucie pas de ce qui est privé ou public, donc la valeur par défaut choisie sera la valeur par défaut pour les deux.

J'utilise git pull --rebase beaucoup dans mon dépôt privé, mais même là, il a un inconvénient potentiel, c'est que l'historique de mon HEAD ne reflète plus l'arbre comme je l'ai réellement travaillé.

Donc, pour un grand exemple, supposons que j'exécute toujours des tests et m'assure qu'ils passent avant de faire un commit. Cela a moins de pertinence après avoir fait un git pull --rebase, car il n'est plus vrai que l'arbre de chacune de mes validations ait réussi les tests. Tant que les changements n'interfèrent en aucune façon, et que le code que j'ai extrait a été testé, alors il est probable qu'il voudrait passer les tests, mais nous ne savons pas parce que je ne l'ai jamais essayé. Si l'intégration continue est une partie importante de votre flux de travail, tout type de rebase dans un référentiel qui est CIed est troublant.

Cela ne me dérange pas vraiment, mais cela dérange certaines personnes: ils préféreraient que leur histoire dans git reflète le code sur lequel ils ont réellement travaillé (ou peut-être au moment où ils le poussent, une version simplifiée de la vérité après une certaine utilisation de "correction").

Je ne sais pas si ce problème en particulier est la raison pour laquelle Linus a choisi de fusionner plutôt que de rebaser par défaut. Il pourrait y avoir d'autres inconvénients que je n'ai pas rencontrés. Mais comme il n'a pas peur d'exprimer son opinion dans le code, je suis sûr que cela revient à ce qu'il pense être un flux de travail approprié pour les personnes qui ne veulent pas trop y penser (et en particulier celles qui travaillent dans un public plutôt qu’un repo privé). Éviter les lignes parallèles dans le joli graphique, en faveur d'une ligne droite propre qui ne représente pas le développement parallèle tel qu'il s'est produit, n'est probablement pas sa priorité même si c'est la vôtre :-)

6
Steve Jessop