L'un des avantages de l'utilisation d'un DVCS est le flux de travail edit-commit-merge (par rapport à edit-merge-commit souvent appliqué par un CVCS). En autorisant chaque modification unique à être enregistrée dans le référentiel indépendamment des fusions, le DAG reflète avec précision le véritable pedigree du projet.
Pourquoi tant de sites parlent-ils de vouloir "éviter les commits de fusion"? La fusion pré-commit ou la refonte post-fusion ne rendent-elles pas plus difficile l'isolement des régressions, l'annulation des modifications passées, etc.?
Point de clarification: le comportement par défaut d'un DVCS est de créer des commits de fusion. Pourquoi tant d’endroits parlent-ils du désir de voir une histoire de développement linéaire qui cache ces engagements de fusion?
la source
git pull
)? Je peux comprendre pourquoi cela pourrait poser problème, mais ma question concerne tous les commits de fusion.git pull --rebase == svn up
(égaux lâches, pas égaux stricts)Réponses:
Les gens veulent éviter les commits de fusion parce que cela rend le journal plus joli. Sérieusement. Cela ressemble aux journaux centralisés avec lesquels ils ont grandi et localement, ils peuvent faire tout leur développement dans une seule branche. Outre cette esthétique, il n'y a aucun avantage, et plusieurs inconvénients en plus de ceux que vous avez mentionnés, tels que le rendre sujet à des conflits est directement lié à un collègue sans passer par le serveur "central".
la source
En deux mots:
git bisect
Un historique linéaire vous permet d'identifier la source réelle d'un bogue.
Un exemple. Ceci est notre code initial:
La branche 1 effectue une refactorisation telle qu’elle
arg
n’est plus valide:La branche 2 a une nouvelle fonctionnalité qui doit utiliser
arg
:Il n'y aura pas de conflits de fusion, cependant un bogue a été introduit. Heureusement, celui-ci sera pris dans l’étape de compilation, mais nous n’avons pas toujours cette chance. Si le bogue se manifeste par un comportement inattendu plutôt que par une erreur de compilation, il se peut que vous ne le trouviez pas avant une semaine ou deux. À ce point,
git bisect
à la rescousse!Oh merde. Voici ce qu'il voit:
Ainsi, lorsque nous envoyons
git bisect
chercher le commit qui a cassé la construction, il va localiser un commit de fusion. Cela aide un peu, mais il s’agit essentiellement d’un paquet d’engagements, pas d’un seul. Tous les ancêtres sont verts. Par contre, avec le rebasement, vous obtenez un historique linéaire:Maintenant, nous
git bisect
allons pointer sur la fonctionnalité exacte qui a cassé la construction. Idéalement, le message de validation expliquera ce qui était prévu pour faire un autre refactor et corriger le bogue immédiatement.L'effet n'est composé que dans les grands projets lorsque les responsables n'ont pas écrit tout le code; ils ne se souviennent donc pas nécessairement pourquoi une validation donnée a été effectuée / à quoi servait chaque branche. Il est donc très utile d’identifier le commit exact (puis de pouvoir examiner les commits autour de celui-ci).
Cela dit, je préfère (actuellement) encore fusionner. En vous basant sur une branche de publication, vous obtiendrez votre historique linéaire
git bisect
, tout en conservant le véritable historique pour le travail quotidien.la source
gitk --all
est extrêmement utile de voir le flux des commits dans les différentes branches (d’autant plus que j’ai habituellement trois branches à la fois, et que je les bascule chaque jour en fonction de mon humeur chez le temps).bisect
conséquence. Il est assez facile de trouver les commits individuels avec unblame
ou un autrebisect
si vous voulez aller plus loin. Avec une histoire linéaire, la fusion se fait hors livre, vous ne pouvez donc plus dire qu'une mauvaise fusion était le problème. Cela ressemble à un idiot qui utilise un argument qui n'existe pas, surtout si l'argument a été supprimé plusieurs fois avant. Essayer de comprendre pourquoi il ferait cela est beaucoup plus difficile lorsque vous détruisez l'histoire.En bref, parce que la fusion est souvent un autre endroit où quelque chose ne va pas, et il suffit de le faire une seule fois pour que les gens aient très peur d’en avoir à nouveau (une fois mordu deux fois, si vous voulez).
Supposons donc que nous travaillons sur un nouvel écran de gestion de compte et qu'il s'avère qu'un bogue a été découvert dans le flux de travail Nouveau compte. OK, nous prenons deux chemins distincts: vous terminez la gestion de compte et je corrige le bogue avec de nouveaux comptes. Puisque nous traitons tous les deux avec des comptes, nous travaillons avec un code très similaire - nous avons peut-être même dû ajuster les mêmes éléments de code.
Nous disposons actuellement de deux versions différentes mais parfaitement opérationnelles du logiciel. Nous avons tous deux validé nos modifications, testé consciencieusement notre code et, indépendamment, nous sommes très confiants d'avoir accompli un travail remarquable. Maintenant quoi?
Eh bien, il est temps de fusionner, mais ... merde, que se passe-t-il maintenant? Nous pourrions très bien passer de deux ensembles de logiciels de travail à un, un logiciel récemment bogué, unifié et horriblement cassé, dans lequel la gestion de votre compte ne fonctionne pas et où les nouveaux comptes sont brisés et je ne sais même pas si l'ancien bogue existe toujours. .
Peut-être que le logiciel était intelligent et qu'il disait qu'il y avait un conflit et insistait pour que nous le guidions. Eh bien, merde - je m'assieds pour le faire et vois que vous avez ajouté un code complexe que je ne comprends pas immédiatement. Je pense que cela entre en conflit avec les modifications que j'ai apportées ... Je vous le demande, et quand vous avez une minute, vous vérifiez et vous voyez mon code que vous ne comprenez pas. Nous devons prendre le temps de nous asseoir, de procéder à une fusion correcte et éventuellement de réessayer le problème pour nous assurer de ne pas le rompre.
En attendant, 8 autres types utilisent tous le même code que les sadiques, j’ai fait quelques petites corrections de bugs et les ai soumises avant que je sache que nous avions un conflit de fusion et il me semble que c’est un bon moment pour faire une pause, et peut-être vous sont partis pour l'après-midi ou coincés dans une réunion ou autre chose. Peut-être que je devrais juste prendre des vacances. Ou changer de carrière.
Et ainsi, pour échapper à ce cauchemar, certaines personnes ont très peur de l'engagement (quoi de neuf, de nouveau?). Nous sommes naturellement peu enclins à prendre des risques dans des scénarios comme celui-ci - à moins que nous ne pensions que nous soyons nuls et que nous allions le gâcher quand même, auquel cas les gens commenceraient à agir avec un abandon inconsidéré. soupir
Alors voilà. Oui, les systèmes modernes sont conçus pour atténuer cette douleur, et il est supposé pouvoir facilement faire marche arrière et se rebaser et se rabaisser, ainsi que la freebase et la hanglide.
Mais tout cela demande plus de travail, et nous voulons simplement appuyer sur le bouton du four à micro-ondes et préparer un repas de 4 plats avant d'avoir le temps de trouver une fourchette. Tout cela semble si insatisfaisant. significatif, mais gérer avec élégance une fusion ne compte tout simplement pas.
En règle générale, les programmeurs doivent développer une excellente mémoire de travail, puis ont tendance à immédiatement oublier tous ces noms de junk et de variable et leur champ d’application dès qu’ils ont résolu le problème, et lorsqu’un conflit de fusion fusion mal gérée) est une invitation à vous rappeler votre mortalité.
la source
Le changement de base fournit un point de branche mobile qui simplifie le processus de transfert des modifications vers la ligne de base. Cela vous permet de traiter une branche longue en cours d'exécution comme s'il s'agissait d'un changement local. Sans refonte de la base, les branches accumulent les modifications par rapport à la référence, qui seront incluses dans les modifications fusionnées à la référence.
La fusion laisse votre ligne de base au point de branche d'origine. Si vous fusionnez quelques semaines de modifications par rapport à la ligne sur laquelle vous avez dérivé, vous avez maintenant de nombreux changements à partir de votre point de branche, dont beaucoup se trouveront dans votre ligne de base. Cela rend difficile l'identification de vos modifications dans votre branche. Le fait de repousser les modifications dans la base peut générer des conflits sans lien avec vos modifications. En cas de conflit, il est possible de pousser des modifications incohérentes. Les fusions en cours nécessitent des efforts de gestion et il est relativement facile de perdre des modifications.
Rebase déplace votre point de branche vers la dernière révision de votre référence. Tous les conflits que vous rencontrerez seront uniquement pour vos changements. Pousser les changements est beaucoup plus simple. Les conflits sont traités dans la branche locale par une nouvelle base. Dans le cas de poussées contradictoires, le dernier à pousser leur changement devra résoudre le problème avec leur changement.
la source
Les outils automatisés s'assurent de mieux en mieux que le code de fusion soit compilé et exécuté, évitant ainsi les conflits syntaxiques , mais ils ne peuvent garantir l'absence de conflits logiques pouvant être introduits par les fusions. Ainsi, une fusion «réussie» vous donne un sentiment de fausse confiance, alors qu'en réalité elle ne garantit rien et que vous devez refaire tous vos tests.
Le vrai problème avec les ramifications et les fusions, à mon avis, est que cela donne le coup d'envoi à la proverbiale possibilité. Cela vous permet de dire "Je vais juste travailler dans mon propre petit monde" pendant une semaine et de régler les problèmes qui surviendront plus tard. Mais réparer les bugs est toujours plus rapide / moins cher quand ils sont frais. Au moment où toutes les branches de code commencent à être fusionnées, vous pouvez déjà oublier certaines des nuances de ce qui a été fait.
Si vous combinez les deux problèmes susmentionnés, vous vous retrouverez peut-être dans une situation où il est plus simple et plus simple de laisser tout le monde travailler dans le même coffre et de résoudre en permanence les conflits à mesure qu'ils surviennent, même s'ils ralentissent un peu le développement actif.
la source
Un autre point pertinent est le suivant: avec le changement de base, je peux facilement sélectionner ou annuler une fonctionnalité dans ma branche de publication.
la source
git cherry-pick -x <commit>
appliquons à la branche de publication. Ou, nous pourrions vouloir annuler quelque chose pour la publication, avecgit revert <commit>
. Si<commit>
c'est une fusion, ça devient poilu. Il est possible pour autant que je sache, mais pas facile à faire. Lorsque vous utilisez rebase, chaque "fusion" est un géant mais un commit régulier, facilement sélectionnable et réversible.Trois choses ne sont dites dans aucune des réponses:
Diffing à l'intérieur d'une branche:
Fusionner un élément à la fois:
Nettoyage avant poussée:
la source