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

71

Considérez la situation suivante:

  • Vous avez un clone d'un dépôt git
  • Vous avez des commits locaux (commits qui n'ont encore été poussés nulle part)
  • Le référentiel distant a de nouveaux commits que vous n'avez pas encore rapprochés

Donc, quelque chose comme ça:

Engagements sans fusion

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

fusionner

C'est parce que git a effectué une fusion.

Il y a une alternative, cependant. Vous pouvez dire tirer pour faire une rebase à la place:

git pull --rebase

et vous obtiendrez ceci:

rebasé

À mon avis, la version rebasée présente de nombreux avantages, notamment centrés sur la propreté de votre code et de l'historique, je suis donc 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 la simple histoire que vous obtenez en retour.

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

La principale motivation de cette question est que mon entreprise essaie d'établir des normes de base (mieux comme des lignes directrices) sur la manière dont nous organisons et gérons nos référentiels afin de permettre aux développeurs de s'approcher plus facilement d'un référentiel avec lequel ils n'ont jamais travaillé auparavant. Je suis intéressé à présenter un argument selon lequel nous devrions normalement nous rebaser dans ce type de situation (et probablement pour recommander aux développeurs de définir leur configuration globale sur rebase par défaut), mais si je m'opposais à cela, je demanderais certainement pourquoi rebase n'est pas compatible. t le défaut si c'est si grand. Je me demande donc s'il manque quelque chose.

Il a été suggéré que cette question est un double de Pourquoi tant de sites préfèrent « rebasage git » sur « git merge »? ; Cependant, cette question est un peu à l’ inverse de celle-ci. Il traite des avantages de la fusion sur la fusion, alors que cette question porte sur les avantages de la fusion sur la fusion. Les réponses qui y figurent reflètent cela, en mettant l’accent sur les problèmes de fusion et les avantages de la réassurance.

jpmc26
la source
L’autre problème est que si vous vous engagez accidentellement à maîtriser, réalisez un pull qui a fusionné, les deux maîtres peuvent ne pas être synchronisés même si la fusion semble normale. C'est pourquoi mon pseudo pull inclut --ff-only.
Ixrec
Si sourcetree change jamais sa vue graphique afin d'afficher les rebases / fusions différemment, allez-vous passer à la fusion?
Ewan
1
@Ewan SourceTree ne devrait pas changer sa vue graphique. Il représente avec précision le graphique.
Jpmc26
4
Pour les électeurs dupes, veuillez noter que le contenu de la réponse que j’ai acceptée n’est absolument pas présent dans la question que vous prétendez être un doublon.
Jpmc26

Réponses:

56

Il est difficile de savoir avec certitude pourquoi la fusion est la valeur par 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 acceptable de - freiner chaque tirant. Écoutez comment ça sonne. "Rebase chaque pull." Cela sonne mal si vous utilisez des demandes de tirage ou similaires. Souhaitez-vous rebaser sur une demande de traction?

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 en aval, des contributeurs, etc.

  • Vous pouvez travailler sur des fonctionnalités en étroite collaboration avec d'autres développeurs, en tirant dessus ou à partir d'une branche de sujet partagée et encore parfois mises à jour à partir de l'amont. Si vous modifiez toujours votre compte, vous finissez par modifier 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 principal. Donc, le défaut est logique.

  • Les développeurs qui ne savent pas quand il est correct de rebaser fusionneront par défaut.
  • Les développeurs peuvent rebaser quand ils le souhaitent.
  • Les commitants qui tirent beaucoup et qui en tirent beaucoup ont la valeur par défaut qui leur convient le mieux.

Pour en savoir plus sur l'intention, voici un lien vers un courrier électronique bien connu de Linus Torvalds avec son point de vue sur le moment où ils ne devraient pas se rebaser. Dri-devel git pull email

Si vous suivez tout le fil, vous pouvez voir qu'un développeur tire d'un autre développeur et que Linus tire de chacun d'eux. Il rend son opinion assez claire. Puisqu'il a probablement décidé des défauts de Git, cela pourrait expliquer pourquoi.

Beaucoup de gens utilisent maintenant Git de manière centralisée, chaque membre d'une petite équipe ne tirant que depuis un dépôt central en amont et poussant vers la même télécommande. Ce scénario évite certaines des situations dans lesquelles un rebasement n'est pas bon mais ne les élimine généralement pas.

Suggestion: Ne définissez pas de stratégie de modification des paramètres par défaut. Chaque fois que vous mettez Git en relation avec un grand groupe de développeurs, certains développeurs ne comprendront pas tout à fait Git (y compris moi-même). Ils vont consulter Google, SO, obtenir des conseils sur les livres de recettes, puis se demander 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.

joshp
la source
5
+1 pour ne pas changer la valeur par défaut - plutôt que de lancer votre propre flux de travail git, il vaut probablement mieux en saisir un qui existe (par exemple, l'un de ceux documentés par atlassian atlassian.com/git/tutorials/comparing-workflows/… )
Rob Church
1
Merci d'avoir répondu. Ce qui me manquait, c’était l’information sur le retrait de l’aval. De plus, il est intéressant de noter que le lien que vous avez donné encourage exactement ce que je voudrais réaliser: "Les gens peuvent (et devraient probablement) rebaser leurs arbres privés (leur propre travail)".
Jpmc26
2
@jpmc Great. En effet. Remettre en place des arbres privés peut éviter toute distraction dans l’histoire commune. Je le fais. C'est la clarté sur quand ne pas le faire qui est important.
Joshp
"certains développeurs ne comprendront pas Git si profondément". Rebase n'est PAS une fonctionnalité très sophistiquée ("profonde", etc.) de Git. Pensez-vous vraiment que cette chose est difficile à comprendre? Je pense que cela devrait être un déclencheur pour appeler dev incompétent.
Victor Yarema
15

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

Redéfinir la base (ou toute autre forme de réécriture) d'une branche sur laquelle d'autres ont travaillé est une mauvaise idée: toute personne en aval de celle-ci est obligée de corriger manuellement son historique. Cette section explique comment effectuer le correctif du point de vue de l’aval. La vraie solution, cependant, serait d’éviter de rebaser l’amont en premier lieu.

Je pense que cela le dit suffisamment pour justifier de ne pas utiliser de rebase, et encore moins de le faire automatiquement à chaque pull. Certaines personnes considèrent que le rebasement est nocif . Cela n’aurait peut-être pas du être fait, car tout ce qu’il semble, c’est de rendre l’histoire plus agréable, ce qui ne devrait pas être nécessaire dans aucun SCM dont le seul travail essentiel est de préserver l’histoire.

Quand vous dites "garder l'histoire propre", pensez que vous avez tort. Cela peut paraître plus joli, mais pour un outil conçu pour conserver l'historique des révisions, il est beaucoup plus propre de garder chaque commit afin que vous puissiez voir ce qui s'est passé. Désinfecter l’histoire par la suite, c’est comme éliminer la patine, donner à une riche antiquité une reproche brillante :-)

gbjbaanb
la source
3
@Ewan IMHO "ne fonctionne pas mais est joli" est quelque chose qui devrait être exclusivement réservé à l'industrie de la mode et non à l'informatique. IMHO git devrait l'enlever car cela encourage évidemment trop de gens à penser que le style est plus important que la substance.
gbjbaanb
12
Je contesterais votre suggestion selon laquelle maintenir l’histoire épurée est inutile. Ce n'est pas. Un historique de référentiel est destiné à la consommation humaine et, en tant que tel, sa plus grande utilité est de le rendre lisible. Dans mon cas d'utilisation particulier, nous pensons même que les chefs de projet non développeurs devraient pouvoir lire l'historique. Un historique vierge ne peut que contribuer à cela, et cela peut aider un nouveau développeur qui n'a jamais vu la base de code et doit plonger et résoudre un bogue pour comprendre ce qui s'est passé dans un domaine particulier du code.
Jpmc26
3
Le code existe avant tout pour être exécuté par une machine (éventuellement après compilation). En appliquant votre philosophie ci-dessus, nous concluons que la lisibilité du code n'a pas d'importance, car aucune lisibilité ne résoudra la difficulté de comprendre le code. Je n'ai jamais suggéré que quoi que ce soit soit écrasé. Je dis simplement qu’il est difficile de suivre un graphique complexe qui divise en de nombreux points de croisement, il est donc intéressant d’investir un peu dans la préservation de votre historique. Notez également qu’un historique linéaire est plus propice à l’utilisation d’outils géniaux tels que blâme et bissect.
Jpmc26
6
Les docs ne disent pas "ne rebase pas". Il est dit "ne rebasez pas les changements en amont des autres ". Il y a un monde de différence entre ces deux. Linus lui - même conseille une rebasage pour l' organisation de l' histoire, comme on peut le voir dans le lien dans la réponse acceptée. Et comment un outil peut-il savoir quels commits ne sont pas pertinents (surtout si les outils ont du mal à analyser une histoire non linéaire!), Et comment sauriez-vous quel commet vous voulez différencier (surtout sans pouvoir fouiller dans l'historique!)? Vous prenez un mot de prudence sur une situation spécifique à un extrême dogmatique.
jpmc26
4
Vous ne voulez certainement pas "garder l'historique des révisions" si cela inclut chaque commit qu'un développeur a jamais fait. En suivant cette logique, nous devrions également enregistrer la version originale du code chaque fois que la touche de retour arrière a été appuyée. Chaque commit doit être un changement minimal et complet qui garde le projet entier dans un état stable. Si par la suite, votre commit original s'avère être bogué, il est bien mieux de rebaser / éditer / amender le commit, que d'en créer un autre. Cependant, voir aussi mail-archive.com/[email protected]/msg39091.html
Mikko Rantalainen
12

Vous avez raison, en supposant que vous ne possédez qu'un seul référentiel local / modifié. Cependant, considérons qu'il existe un deuxième PC local, par exemple.

Une fois que votre copie locale / modifiée est insérée quelque part, le fait de re-baser le fichier va tout gâcher. Bien sûr, vous pouvez forcer, mais cela devient vite compliqué. Qu'advient-il si un ou plusieurs d'entre eux ont un autre commit complètement nouveau?

Comme vous pouvez le constater, la situation est très différente, mais la stratégie de base me semble beaucoup plus pratique dans les cas non spéciaux / de collaboration.


Deuxième différence: la stratégie de fusion conservera une structure claire et cohérente dans le temps. Après avoir modifié les bases, il est très probable que les anciens commits suivent des modifications plus récentes, rendant l’ensemble de l’histoire et son déroulement plus difficiles à comprendre.

Mario
la source
1
"Après les modifications de base, il est très probable que les anciens commits suivent des modifications plus récentes" - cela se produit également avec les fusions, c’est pourquoi vous avez (peut-être) besoin du joli graphique pour le comprendre. Le moment où une validation a été effectuée peut être long avant la fusion qui l’a amenée dans cette branche.
Steve Jessop
6

La principale raison est probablement que le comportement par défaut devrait "fonctionner" dans les pensions publiques. Ré-baser l’histoire que d’autres personnes ont déjà fusionnée va leur causer des ennuis. Je sais que vous parlez de votre pension privée, mais en règle générale, git ne sait pas ce qui est privé ou public, alors le défaut choisi sera celui par défaut pour les deux.

J'en utilise git pull --rebasebeaucoup dans mes pensions privées, mais même dans ce cas, il y a un inconvénient potentiel: l'historique de mon travail HEADne correspond plus à l'arbre, mais à mon travail.

Donc, pour un grand exemple, supposons que j’exécute toujours des tests et s’assure qu’ils passent avant de faire un commit. Cela a moins de pertinence après que je fasse un git pull --rebase, car il n’est plus vrai que l’arbre de chacun de mes commits a réussi les tests. Tant que les modifications n'interfèrent en aucune manière et que le code que j'ai extrait a été testé, il est présumé que les tests seraient satisfaisants, mais nous ne le savons pas car je ne l'ai jamais essayé. Si l'intégration continue est une partie importante de votre flux de travail, toute forme de rebase dans un référentiel auquel un CI est affecté est troublante.

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

Je ne sais pas si cette question en particulier est la raison pour laquelle Linus a choisi de fusionner plutôt que de rebasonner par défaut. Il pourrait y avoir d'autres inconvénients que je n'ai pas rencontrés. Mais comme il n'hésite pas à exprimer son opinion dans le code, je suis presque 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 travaillant dans un environnement public). qu'un repo privé). Éviter les lignes parallèles dans le joli graphique, en faveur d'une ligne droite nette qui ne représente pas le développement parallèle en tant que tel, n'est probablement pas sa priorité même si c'est la vôtre :-)

Steve Jessop
la source