Git pull entraîne des messages "Merge branch" superflus dans le journal de validation

110

Je travaille avec un autre développeur sur un projet et nous utilisons Github comme dépôt distant. Je suis sur un Mac utilisant git 1.7.7.3, il est sous Windows avec git 1.7.6.

C'est ce qui se passe

  1. L'un de nous (appelons-le développeur A, mais peu importe lequel) pousse un ensemble de commits vers GitHub.
  2. L'autre (développeur B) fait des commits locaux.
  3. B fait un git pull.
  4. B fait un git push.
  5. En regardant le journal de l'historique des validations, je vois Merge branch 'master' de github.com:foo/bar

Le journal de validation est jonché de messages "Fusionner la branche" au fil du temps, et montre également que le développeur B commet les modifications apportées par le développeur A. Le seul moyen que nous avons trouvé pour éviter ce problème a été de faire un git pull --rebaseà l'étape 3, mais je ne sais pas quels effets secondaires le rebasage introduira. C'est la première fois que je travaille sur un dépôt git multi-développeurs, est-ce donc juste un comportement normal? Des idées sur la façon de résoudre ce problème?

mshafrir
la source
2
Vous pouvez afficher le journal sans fusion avecgit log --no-merges
wjandrea

Réponses:

88

Le commit que vous voyez est parfaitement bien. A pulls'exécute efficacement git fetch, puis git mergeune fusion se produit généralement lorsque vous exécutez git pull.

L'alternative d'utiliser le rebasage au lieu de la fusion est possible, mais vous devez généralement l'éviter. Le rebasage vous permet de conserver un historique linéaire, mais supprime également toute information sur le branchement qui s'est produit à l'origine. Cela entraînera également la réécriture de l'historique de la branche actuelle, recréant tous les commits qui ne sont pas contenus dans la branche cible (dans votre cas, la télécommande). Comme les commits recréés sont des commits différents , cela peut causer beaucoup de confusion lors du développement avec d'autres, en particulier lorsque les gens ont déjà extrait des parties de ces commits avant qu'ils ne soient réécrits (par exemple avec des branches de fonctionnalités). Donc, en règle générale, vous ne devriez jamais réécrire un commit qui a déjà été poussé.

Les commits que vous voyez sont là pour combiner deux (ou plus) branches. C'est parfaitement bien d'avoir un commit qui ne fait rien d'autre que de fusionner plusieurs branches. En fait, cela est très clair lorsque vous avez un commit de fusion qui combine des branches lorsque vous regardez l'historique. Par rapport au rebasage, la fusion vous permet également de voir efficacement l' historique d' origine tel qu'il a été développé, y compris les branches réelles qui coexistaient.

Donc, pour faire court: oui, avoir des validations de fusion est parfaitement bien et vous ne devriez pas vous en soucier.

poussée
la source
2
Très bonne réponse. J'ai moi-même essayé le style rebase car il était recommandé dans certaines directives de contribution de projets open source, et cela m'a causé des problèmes. Un nouveau membre de l'équipe avait la même chose. Je pense que l'option de rebase n'est pas pour les équipes travaillant ensemble toute la journée, mais est correcte pour les projets qui ont des contributeurs principaux et d'autres contributeurs qui ne font que soumettre des correctifs. Ceux-ci devraient aller chercher le dépôt principal et rebaser leurs modifications juste avant d'émettre une pull request.
Meligy
2
@sTodorov S'il n'y a pas de nouvelles modifications, la partie extraction de l'extraction ne fera rien, mais la fusion est toujours en cours d'exécution. Donc, si votre succursale locale actuelle n'est pas à jour, elle fusionnera les nouvelles modifications dans votre succursale. Et s'il ne peut pas faire une fusion rapide (si vous avez des commits divergents), alors il créera un commit de fusion.
poke
28
Cette réponse donne l'impression que l'utilisation de rebase comme l'OP l'a décrit est dangereuse, mais ce n'est pas le cas. La réinitialisation à l'étape 3 ne réécrit pas l'historique entier. Seuls les commits locaux qui n'ont pas été poussés sont réécrits en étant réappliqués au-dessus du nouveau HEAD (le dernier commit poussé vers cette branche). Cela empêche les validations de fusion superflues et n'a aucun autre effet secondaire.
bob esponja
1
@bobesponja Tous les commits qui ne sont pas sur la branche distante extraite sont réécrits. Cela peut inclure des commits publiés à partir d'autres branches, par exemple avec des branches de fonctionnalités, auxquelles d'autres peuvent déjà avoir accédé auparavant. En tant que tel, oui, rebaser sans penser à ce que vous rebasez est quelque peu dangereux.
poke le
1
@bobesponja Oui, si vous publiez votre branche de fonctionnalités tôt (parce que d'autres travaillent dessus, ou simplement en tant que sauvegarde), vous ne devriez pas la rebaser car d'autres pourraient déjà l'avoir récupérée. Rebaser alors - comme vous le dites vous-même - va à l'encontre des directives de rebasage que j'ai énoncées dans ma réponse. Cependant, si vous ne publiez pas vos commits, le rebasage est parfait si vous voulez et ne vous souciez pas de l'historique linéaire. Mais cela dépend de la façon dont vous travaillez, donc la réponse générale est de l'éviter à moins que ce ne soit vraiment sûr. Btw. J'ai révisé ma réponse, donc si le problème est résolu, j'apprécierais que vous supprimiez votre vote défavorable.
poke le
48

Cette réponse a été révisée, car ma compréhension, les diagrammes et les conclusions étaient incorrects.


git pullprovoque des validations de fusion car git fusionne. Cela peut être changé en paramétrant vos branches pour utiliser le rebase au lieu de la fusion. L'utilisation du rebase au lieu de la fusion sur une extraction fournit un historique plus linéaire au référentiel partagé. D'autre part, les commits de fusion montrent les efforts de développement parallèles sur la branche.

Par exemple, deux personnes travaillent sur la même succursale. La branche commence comme:

...->C1

La première personne termine son travail et pousse à la succursale:

...->C1->C2

La deuxième personne termine son travail et veut pousser, mais ne peut pas parce qu'elle doit mettre à jour. Le référentiel local de la deuxième personne ressemble à ceci:

...->C1->C3

Si l'extraction est définie pour fusionner, le deuxième référentiel de personnes ressemblera à.

...->C1->C3->M1
      \      /
       ->C2->

Où M1 est un commit de fusion. Cette nouvelle histoire de branche sera poussée vers le repo. Si à la place, l'extraction est définie pour rebaser le dépôt local ressemblerait à ceci:

...->C1->C2->C3

Il n'y a pas de validation de fusion. L'histoire a été rendue plus linéaire.

Les deux choix reflètent l'histoire de la succursale. git vous permet de choisir l'historique que vous préférez.

Il existe en effet des endroits où le rebase peut poser problème avec les branches distantes. Ce n'est pas un de ces cas. Nous préférons utiliser rebase car il simplifie un historique de branche déjà compliqué et montre une version de l'historique relative au référentiel partagé.

Vous pouvez définir branch.autosetuprebase = always pour que git établisse automatiquement vos branches distantes en tant que rebase au lieu de master.

git config --global branch.autosetuprebase always

Ce paramètre oblige git à créer automatiquement un paramètre de configuration pour chaque branche distante:

branch.<branchname>.rebase=true

Vous pouvez le définir vous-même pour vos succursales distantes déjà configurées.

git config branch.<branchname>.rebase true

Je tiens à remercier @LaurensHolst pour ses questions et pour la suite de mes déclarations précédentes. J'ai certainement appris plus sur le fonctionnement de git avec les commits pull et merge.

Pour plus d'informations sur les validations de fusion, vous pouvez lire Contribuer à un projet dans ProGit-Book . La section Petite équipe privée affiche les validations de fusion.

Bill porte
la source
7
«L'utilisation du rebase au lieu de la fusion sur une extraction fournit l'historique correct au référentiel partagé. L'utilisation de la fusion fournit un faux historique. » - Quelle est la justification de cette déclaration plutôt audacieuse? Il n'y a aucun moyen qu'une histoire avec des fusions soit une «fausse histoire». C'est une représentation précise de l'ordre dans lequel les choses se sont passées. Ce que vous faites en rebasant, c'est en fait une modification de l' histoire, pour en créer une version légèrement plus linéaire. Vous sacrifiez la précision à l'esthétique. Peut-être quelque chose que vous préférez faire, mais en aucun cas plus véridique.
Laurens Holst
2
Utiliser le rebase au lieu de la fusion ne sacrifie pas la précision à l'esthétique. Nous utilisons --no-ff pour les fusions, donc l'esthétique n'est pas une exigence. La précision est un désir. Rebase fournit cette précision.
Bill Door
2
Comment l'histoire rebasée est-elle plus précise? Vous ne clarifiez pas cela, et je ne vois pas comment ce serait.
Laurens Holst
1
L'historique est le reflet du moment auquel les commits se sont produits dans le repo partagé . Un jour 1, le repo partagé a vu commettre C2. Le jour 2, le repo partagé voit le commit C3. Si C3 venait avant C2, le reflet du temps ne serait pas correct. C3 n'est pas venu avant C2. Tout ce que rebase, fait est de réorganiser les commits sur le référentiel local pour refléter correctement l'historique affiché par le référentiel partagé.
Bill Door
6
Vos questions m'ont amené à revoir ma compréhension des commits de fusion. Mon schéma est incorrect. Je révise la discussion. Mes conclusions sont également incorrectes. L'historique du rebase et de la fusion est également correct. Vous pouvez faire votre propre choix.
Bill Door le
11

Tu peux faire:

git pull --rebase

Cependant, cela placera toujours vos modifications au-dessus de celles de vos collaborateurs. Mais vous ne recevrez aucun message de fusion polluant.

joyeux
la source
9

Il existe en fait une réponse beaucoup plus simple à cela. Demandez simplement au développeur B de faire un pull AVANT de faire sa validation. Cela empêchera ces validations de fusion, car elles sont causées par l'historique que vous avez créé sur votre dépôt local à partir de votre validation locale en essayant de fusionner avec l'historique des validations sur le dépôt distant. Si vous recevez un message disant quelque chose du genre `` les modifications seront écrasées '' lors d'une extraction, cela signifie simplement que vous avez tous les deux touché le même fichier, alors faites:

git stash
git pull
git stash pop

alors vous pouvez résoudre tous les conflits de fusion s'il y en a.

Luke
la source
Le plus ennuyeux et anxieux sont exactement les conflits de fusion. Je préfère l'éviter
Vert
1
@Green Si vous êtes préoccupé par les conflits de fusion, même git pull n'est pas différent.
Zoso
Sauf cette fois où vous oubliez stashavant vous pull. Ugh git m'oblige à être au top de mon jeu tout le temps.
linuxNoob
Besoin d' git pull --rebaseintégrer les modifications à distance avant les modifications locales, peu importe.
vonbrand
7

Faire un git pull insérera les messages "Merge branch", c'est exactement ce qu'il fait. En effectuant un git pull, vous avez fusionné la branche distante dans votre branche locale.

Lorsque vous effectuez une extraction git et qu'il y a des conflits, le journal git affichera les mises à jour des fichiers en conflit comme provenant de l'utilisateur qui a résolu les conflits. Je suppose que c'est parce que la personne qui résout le conflit réengage le fichier.

Autant que je sache, c'est comme ça que fonctionne git, et il n'y a pas moyen de contourner cela.

Le rebasage épatera l'historique de git, vous ne pourrez donc pas voir quand les fusions ont eu lieu.

Kclair
la source