web-dev-qa-db-fra.com

Les développeurs chevronnés doivent-ils encore gérer les conflits de fusion?

Je suis toujours ingénieur logiciel en formation, mais j'ai entendu à plusieurs reprises l'adage suivant:

Les bons codeurs n'ont pas à gérer les conflits de fusion.

Chaque fois que je travaille sur un projet avec d'autres, je perds beaucoup de temps et d'efforts à résoudre les conflits de fusion. Alors, j'ai commencé à me demander à quel point cet adage est vrai. Je connais des techniques comme GitFlow et agile qui permettent aux développeurs de fractionner efficacement leur travail, de s'engager plus souvent et de maintenir plusieurs branches de code, donc les conflits de fusion sont beaucoup moins probables. Mais ils se produisent sûrement encore et peuvent potentiellement faire des ravages?

En d'autres termes, combien de temps et d'efforts les développeurs chevronnés perdent-ils pour résoudre les conflits de fusion (quand ils pourraient travailler sur leurs projets)? Les techniques disponibles sont-elles capables d'annuler réellement les effets des conflits de fusion?

57
lemeneux

Je pense qu'il est un peu fallacieux de dire que les bons développeurs n'ont jamais de conflits de fusion, mais ils peuvent sûrement réduire le nombre de fois que cela se produit. Il est également très important de se rappeler que le développement de logiciels est une activité d'équipe. Les actions d'autres membres des équipes peuvent également augmenter ou diminuer la probabilité de conflits de fusion.

Tout d'abord, il est important de comprendre les façons courantes dont les conflits de fusion se produisent:

  • Deux personnes apportent des modifications différentes à la même ligne de code
  • Quelqu'un décide de reformater l'intégralité du fichier afin que chaque ligne soit modifiée
  • Supprimer un fichier puis le remplacer (c'est un conflit d'arborescence)
  • Le code est supprimé et ajouté en même temps par deux personnes différentes (ce qui n'est pas rare avec Visual Studio .vsproj des dossiers)

Développement équipes ont trouvé des moyens d'éviter ces situations:

  • Assurez-vous que chaque membre de l'équipe travaille dans différentes parties du code (c'est-à-dire gérées dans l'attribution des tâches)
  • Normes de code qui déterminent si vous utilisez des espaces ou des tabulations, des normes de dénomination, etc., de sorte que le reformatage de code complet n'est pas nécessaire
  • GitFlow pour que tout le monde travaille sur sa propre branche et puisse résoudre les conflits à l'étape Pull Request (toutes les fusions en aval fonctionnent à merveille)
  • S'engager souvent et fusionner régulièrement de develop pour s'assurer que votre branche de fonctionnalité n'est jamais trop à jour
  • Assurez-vous que vos fonctionnalités sont suffisamment petites, elles peuvent être effectuées en 1 à 3 jours.

Avec de tels changements, vous pouvez réduire considérablement la probabilité de conflits. Vous ne pourrez jamais les éliminer complètement.

97
Berin Loritsch

La citation est probablement incomplète:

Les bons codeurs n'ont pas à gérer les conflits de fusion ...
... parce que les bons codeurs poussent la force.

Sérieusement, cependant, la seule façon d'éviter les conflits de fusion est de travailler seul (et même cela n'aide pas; il m'est arrivé d'avoir des conflits de fusion avec moi-même sur des projets personnels). Dans une entreprise qui embauche des développeurs expérimentés, il existe cependant trois facteurs qui réduisent la douleur des conflits de fusion:

  1. Excellente communication au sein de l'équipe.

    Autrement dit, vous savez sur quoi vos collègues travaillent et ils savent ce que vous faites. Par conséquent, lorsque vous modifiez éventuellement un domaine sur lequel un membre de votre équipe travaille, vous demandez (ou vous dites). De cette façon, vous réduisez considérablement le risque d'un commit douloureux.

    Cela s'applique en particulier à celles des tâches de refactoring qui pourraient affecter de manière substantielle une grande partie de la base de code, ou effectuer des changements qui sont pénibles à fusionner. Supposons que vous modifiez le type d'une variable donnée partout, pendant que votre collègue implémente une fonctionnalité dans laquelle cette variable est utilisée. Non seulement vous risquez d'avoir un conflit de fusion douloureux, mais aussi de casser la construction pendant la fusion.

  2. Grande architecture.

    Si vous travaillez sur une base de code héritée avec des fichiers 4K-LOC et que vous avez besoin de toute modification de base pour modifier des dizaines de fichiers, il y a des chances qu'à chaque changement, vous obtiendrez un conflit de fusion.

    D'un autre côté, lorsque l'architecture est suffisamment bonne, vous réduisez le risque d'avoir un conflit de fusion à deux situations: (1) où vous modifiez une interface, ou (2) où deux collègues modifient exactement la même partie de l'application . Dans le premier cas, vous communiquez, réduisant encore plus le risque d'une fusion douloureuse. Dans le second cas, vous effectuez une programmation par paires, supprimant complètement la fusion.

  3. Interface appropriée avec d'autres équipes.

    Parfois, il arrive qu'il y ait des conflits de fusion entre différentes équipes. Supposons qu'une équipe modifie un module, tandis qu'une autre modifie le code qui utilise ce module.

    Les développeurs expérimentés auraient tendance à adopter des interfaces appropriées, telles que SOA, ce qui rendrait les parties distinctes du système plus indépendantes sur le plan technique. De plus, ils s'appuieront beaucoup plus sur des pratiques spécifiques telles que les requêtes Push pour éviter de modifier directement le code de quelqu'un d'autre.

    Il s'agit essentiellement des deux premiers points, mais inter-équipes: vous communiquez mieux et vous vous assurez que les pièces sont plus entremêlées.

27
Arseni Mourzenko

Un de mes collègues est tombé sur un développeur qui n'a pas eu à gérer les conflits de fusion.

Il a fait quelques changements, les a fusionnés et quelques jours plus tard, les changements avaient disparu. Il a découvert que quelqu'un d'autre (sur un autre continent également) avait remplacé des fichiers au lieu de fusionner.

Il remit les changements en place, légèrement vexé - et quelques jours plus tard, les changements avaient de nouveau disparu.

C'est à ce moment-là qu'il a eu une longue conversation avec son manager, qui à son tour a eu une longue conversation avec le manager de l'autre équipe, qui peut ou non inclure des menaces de violence physique, et le manager de l'autre équipe a apparemment eu une longue conversation avec le développeur dans question, et le comportement a cessé.

Cela dit, les développeurs expérimentés peuvent éviter certains conflits de fusion.

  1. Lorsque vous renommez un fichier, effectuez une fusion où renommer le fichier (et évidemment les changements causés par cela, comme changer les instructions d'inclusion ou les fichiers de projet) est absolument le seul changement.

  2. Assurez-vous que les paramètres de l'éditeur de tout le monde sont les mêmes, afin de ne pas créer de modifications simplement en regardant le code.

  3. Vous obtenez des conflits de fusion si deux personnes changent de code au même endroit. Donc, si vous ajoutez à un fichier, n'ajoutez pas à la fin, mais ajoutez à l'endroit logiquement correct. De cette façon, si un autre développeur fait de même, les conflits de fusion sont beaucoup moins probables.

  4. Fusionnez de temps en temps la base de code commune dans votre branche, afin de ne jamais avoir de conflits de fusion many. Un conflit est facile, 10 dans une fusion sont un problème.

  5. La fusion de votre branche vers la base de code commune doit jamais provoquer un conflit. C'est parce que vous avez fait (4) juste avant d'essayer de faire la fusion, donc la fusion finira par prendre votre code sans aucun changement.

Juste remarqué: Oui, c'est vrai, les bons développeurs n'ont jamais de conflits de fusion fusionnant de leur branche dans la base de code commune. Parce que tous les conflits de fusion ont été traités plus tôt.

21
gnasher729

Comme d'autres réponses l'ont décrit, les conflits de fusion se produisent indépendamment de l'expérience ou des compétences, et un adage qui prétend qu'il s'agit d'une sorte de faiblesse provenant d'un manque de compétences est ridicule.

D'autres réponses ont noté des façons dont les développeurs qualifiés peuvent apprendre à rendre les conflits de fusion moins probables, en empêchant le chaos de mise en forme, les fusions fréquentes et une meilleure coordination d'équipe, mais je pense qu'il y a du vrai dans le concept plus large que vous soulevez: les développeurs qualifiés peuvent devenir meilleurs gérer les conflits de fusion lorsqu'ils surviennent.

La résolution des conflits de fusion est délicate. Vous devez trouver les conflits, comprendre les marqueurs de conflit, comprendre ce qui a changé de chaque côté compte tenu du contexte du code (impliquant éventuellement des problèmes difficiles à repérer comme le formatage), peut-être rechercher des validations individuelles des deux côtés de la fusion pour comprendre l'intention d'origine, résoudre réellement le conflit, traiter les implications possibles du changement ailleurs dans la base de code (ou même dans d'autres référentiels si des API ou des interfaces sont impliquées), compiler, tester, valider, etc ... Vous devez vous rappeler comment demandez au système de contrôle de version de faire ce que vous voulez pendant ce processus. Et puis il y a des cas plus compliqués: conflits impliquant des fichiers et répertoires déplacés/supprimés; conflits impliquant des fichiers binaires; les conflits impliquant des fichiers générés (y compris des choses comme les fichiers de configuration Visual Studio et Xcode; même si le conflit est simple, le fichier lui-même ne sera pas familier jusqu'à ce que vous en ayez une certaine expérience); conflits assez désagréables où vous allez trouver la personne de l'autre côté de la fusion et le découvrir ensemble; toutes sortes de plaisir.

C'est beaucoup de choses à gérer. Cela peut provoquer un peu de panique: vous roulez avec impatience pour emballer quelque chose, et tout à coup, vous êtes confronté à des messages d'erreur, des trucs ">>>>>>>" étranges au milieu de vos fichiers, et un tas de code inconnu qui est soudainement apparu ailleurs. Comme toute autre tâche de programmation, l'expérience peut aider à développer les compétences pour y faire face plus efficacement et moins douloureusement. La première fois que vous rencontrez un conflit de fusion, c'est une épreuve déroutante, tandis que la 500e fois est plus routinière. Par ce point:

  • Vous êtes habile à utiliser le système de contrôle de version pour obtenir les informations dont vous avez besoin et apporter les modifications que vous souhaitez.
  • Vous connaissez le format de conflit, la lecture des différences et la visualisation des modifications de la fusion.
  • Vous avez peut-être choisi outils, open source ou commercial, pour aider aux fusions et appris à les utiliser efficacement. Ceux-ci peuvent aider énormément, à tel point que je vais le mettre en gras: de bons outils peuvent aider à rendre les conflits de fusion beaucoup moins douloureux .
  • Vous savez quels types de conflits sont typiques dans vos projets (fichiers de configuration IDE, bas de fichiers de chaînes, autres points chauds qui changent fréquemment) et ajustez les processus pour les empêcher ou devenez apte à les résoudre très rapidement. Les conflits courants comme "oh, nous avons tous les deux ajouté de nouvelles chaînes au bas du fichier" deviennent faciles à corriger.
  • Vous pouvez anticiper les types de tâches de refactoring susceptibles de provoquer des conflits avec le reste de votre équipe et vous coordonner pour réduire la douleur.
  • Vous savez quand ne pas fusionner. Si vous tentez une fusion et découvrez que vous avez ajouté un paramètre à une fonction que quelqu'un d'autre a supprimée, il peut être préférable d'arrêter et de repenser votre stratégie en dehors de la portée du processus de résolution des conflits.
  • Vous savez quand vous avez fait un vrai gâchis et il sera plus facile de recommencer la fusion.
  • Vous savez quand la base de code sous-jacente a trop changé pour faire de la "fusion" une description juste de ce que vous faites, vous notez donc les modifications que vous voulez réellement apporter, jetez vos modifications et recommencez avec une nouvelle HEAD propre. Par exemple, si votre changement consiste simplement à ajouter un nouveau fichier image et que, dans l'intervalle, quelqu'un est venu et a transformé toutes les images du projet en images-objets, vous ne fusionnez plus vraiment au lieu de faire la tâche d'une manière différente, alors faites exploser vos efforts précédents et faites-le de la nouvelle façon.

Avec tout cela, la plupart des conflits de fusion deviennent routiniers, donc moins de temps et d'efforts sont consacrés à leur résolution. Ils se produisent toujours et causent parfois une frustration importante, mais causent généralement beaucoup moins de ravages.

6
Zach Lipton

Ce n'est pas tant l'existence de conflits de fusion, mais l'ampleur du problème qu'ils causent.

Les "dommages" des conflits de fusion avec des développeurs inexpérimentés sont considérés comme un énorme problème. Les gens inventent des schémas de contrôle de source fous ou même cessent d'utiliser le contrôle de source tous ensemble pour éviter ces problèmes "massifs".

Mais avec une équipe expérimentée, les conflits de fusion ne posent pratiquement aucun problème et sont résolus rapidement.

Je pense qu'il y a deux différences d'approche principales qui contribuent à cela:

  1. Utiliser le contrôle de source correctement. Branches caractéristiques, beaucoup de petits commits, tirer avant de pousser, tester avant de pousser, etc.

  2. Comprendre les changements des autres peuples. Si vous comprenez les modifications de fonctionnalités et de code qui sont en conflit avec votre modification, la fusion des deux est simple.

Faites attention aux autres tâches lors des stand-ups, discutez avec d'autres personnes de la façon dont ils mettent en œuvre le changement et des points sur lesquels vous pouvez entrer en conflit. Convenez à l'avance de la façon dont les choses devraient fonctionner.

5
Ewan

Intégration continue .

Pour comprendre pourquoi CI aide à considérer que pour expérimenter un conflit de fusion, le ou les changements dans cette branche doivent entrer en conflit avec un ou plusieurs changements sur le maître:

             A  B  C
master    *--*--*--*--*
           \         /
feature-x   *--------

Plus la branche existe depuis longtemps, plus les modifications seront effectuées sur le maître, et donc plus les chances que l'une de ces modifications provoque un conflit (même si la modification sur la branche est très faible):

             A  B  C  D  E  F  G  H
master    *--*--*--*--*--*--*--*--*--*
           \                        /
feature-x   *-----------------------

Il y a diverses choses que nous pouvons faire pour réduire les risques de conflit entre 2 changements (comme éviter de reformater ou organiser soigneusement le travail pour éviter que plusieurs développeurs travaillent sur la même zone), mais l'approche la plus simple consiste à simplement fusionner les changements plus rapidement, en réduisant le nombre de changements effectués sur le maître, et à son tour la possibilité d'un conflit:

             A     B  C
master    *--*--*--*--*--*
           \   /    \   /
feature-x   *--      *--

Si vous pratiquez correctement l'IC, alors tout le monde devrait s'engager dans une branche partagée plusieurs fois par jour , c'est-à-dire une fois toutes les quelques heures. C'est assez rapide pour que la plupart du temps, il n'y ait pas de changements sur master, et encore moins des changements contradictoires. Ce qui est encore mieux, c'est que même si vous voyez un conflit, vos modifications seront minimes et donc la résolution du conflit devrait être relativement simple - dans le pire des cas (où vous devez rejeter et implémenter complètement votre changement), vous avez perdu à la plupart des quelques heures de travail.


Dans les commentaires, il a été suggéré que les développeurs fusionnent régulièrement de master au lieu de master, ce qui est certainement utile, mais pas autant qu'une intégration continue. Par exemple, dans le graphique suivant, chaque validation sur le maître (A, B et C) a une chance d'entrer en conflit avec l'une des validations de la branche (X, Y ou Z), pour un total de 9 conflits potentiels. Fusionner une fois en maître à la fin signifie que les 9 conflits potentiels doivent être résolus en même temps:

             A  B  C
master    *--*--*--*--*
           \         /
feature     *--*--*--
            X  Y  Z

Si au lieu de cela, nous fusionnons de maître dans notre branche de fonctionnalité après chaque changement sur maître:

             A     B     C
master    *--*-----*-----*---*
           \  \     \     \ /
feature     *--*--*--*--*--*
            X     Y     Z

Ensuite, chaque fois que nous fusionnons, nous devons faire face aux conflits suivants:

  • Lors de la première fusion, nous devons résoudre tout conflit entre les commits A et X
  • Dans la deuxième fusion, nous résolvons tous les conflits entre B et X, B et Y
  • Lors de la dernière fusion, nous résolvons tout conflit entre C et X, C et Y, C et Z

Notez cependant que nous n'avons jamais eu besoin de résoudre les conflits entre A et Y, car la modification A a été fusionnée dans notre branche de fonctionnalité avant la modification Y. Au total, nous avons réussi à éviter 3 des 9 conflits de fusion potentiels en fusionnant régulièrement avec le maître.

Notez également que chaque fois que nous fusionnons, le nombre de conflits potentiels augmente - plus la branche de fonctionnalité existe, plus de changements (et donc de conflits potentiels) seront effectués sur le maître, mais le vrai tueur ici est que chaque modification que nous apportons sur la branche de fonctionnalité a un effet multiplicateur sur le nombre de conflits potentiels à chaque fusion.

Voyons maintenant ce qui aurait pu arriver si nous pratiquions l'IC:

             A     B     C
master    *--*--*--*--*--*--*
           \   / \   / \   /
feature     *--   *--   *--
            X     Y     Z

Cette fois, nous avons dû faire face aux conflits de fusion suivants:

  • Lors de la fusion du changement de X en maître, nous avons dû résoudre tout conflit entre A et X
  • Lors de la fusion du changement Y, nous avons dû résoudre tout conflit entre X et V
  • Lors de la fusion de Z, nous avons dû résoudre tout conflit entre Z et C

Comme auparavant, nous n'avons jamais eu besoin de résoudre les conflits entre A et Y, car le changement A était déjà fusionné dans notre branche de fonctionnalité avant de faire le changement Y, mais cette fois nous n'avons pas non plus besoin de fusionner les changements X et B, X et C ou Y et C, en évitant 6 des 9 conflits potentiels.

Voir cette question pour plus d'informations/conseils sur la fusion régulière avec master:

Est-il préférable de fusionner "souvent" ou seulement après la fin de la fusion des branches de fonctionnalités?

1
Justin

"Les programmeurs font des erreurs tout le temps " --- John Carmack

Les personnes qui font des affirmations semblables à "Je suis un développeur" rockstar "" ou "Les bons codeurs n'ont pas à gérer les conflits de fusion ..." sont le plus souvent des poseurs qui semblent être nombreux dans la communauté générale du développement de logiciels. et devrait être sommairement ignoré en tant que tel.

Construire un logiciel qui sera en production utilisé par des personnes réelles en dehors de vous n'est pas une mince affaire. Vous ferez des erreurs ... et les gens avec qui vous travaillez feront souvent des erreurs. Fonder une évaluation de la compétence d'ingénierie de quiconque sur la question de savoir s'ils doivent gérer des conflits de fusion est un non-sens à première vue.

0
user405887

Celui qui a dit cela a en tête une notion particulière de "bon codeur", qui va probablement comme ceci:

  • Le bon codeur travaille seul sur un grand programme qu'il a conçu seul.
  • Il n'y a pas de fourches du programme, ni de branches de publication ou quoi que ce soit de ce genre, et il n'y a donc jamais d'activité de rebasage qui crée des conflits.
  • Lorsque des bogues sont détectés dans les anciennes versions du programme, les utilisateurs mettent à jour consciencieusement la ligne de base actuelle, ou bien les responsables de paquets en aval rétroportent les correctifs requis à partir de la ligne de base actuelle (donc Good Coder ne voit jamais les conflits impliqués).
  • Dans les rares cas où un tiers fournit un correctif ou une amélioration pour le Grand programme, il doit fournir un correctif qui s'applique proprement à la tête de développement actuelle, de sorte que le bon codeur est protégé de tout effort de transfert vers l'avant impliquant la résolution de conflits.
  • Enfin, Good Coder ne réorganise jamais l'ordre de ses commits (comme avec le rebase interactif de git).
0
Kaz