Quels modèles de branchement Git fonctionnent pour vous?

379

Notre entreprise utilise actuellement un modèle de branchement simple tronc / version / correctifs et aimerait savoir quels modèles de branchement fonctionnent le mieux pour votre entreprise ou votre processus de développement.

  1. Workflows / modèles de branchement

    Voici les trois principales descriptions de ce que j'ai vu, mais elles se contredisent partiellement ou ne vont pas assez loin pour trier les problèmes ultérieurs que nous avons rencontrés (comme décrit ci-dessous). Ainsi, jusqu'à présent, notre équipe ne propose pas de solutions aussi géniales. Faites-vous quelque chose de mieux?

  2. Fusion vs rebasage (enchevêtrement vs historique séquentiel)

    Devrait-on pull --rebaseou attendre la fusion avec la ligne principale jusqu'à ce que votre tâche soit terminée? Personnellement, je penche pour la fusion car cela préserve une illustration visuelle de la base sur laquelle une tâche a été lancée et terminée, et je préfère même merge --no-ffà cet effet. Il présente cependant d'autres inconvénients. De plus, beaucoup n'ont pas réalisé la propriété utile de la fusion - qu'elle n'est pas commutative (fusionner une branche de sujet en maître ne signifie pas fusionner maître dans la branche de sujet).

  3. Je recherche un workflow naturel

    Parfois, des erreurs se produisent parce que nos procédures ne capturent pas une situation spécifique avec des règles simples. Par exemple, un correctif nécessaire pour les versions antérieures devrait bien sûr être basé suffisamment en aval pour pouvoir fusionner en amont dans toutes les branches nécessaires (l'utilisation de ces termes est-elle suffisamment claire?). Cependant, il arrive qu'un correctif arrive dans le maître avant que le développeur ne se rende compte qu'il aurait dû être placé plus en aval, et si cela est déjà poussé (pire encore, fusionné ou quelque chose basé sur lui), l'option restante est la sélection des cerises, avec ses périls associés. Quelles règles simples comme celles-ci utilisez-vous?On y trouve également la maladresse d'une branche de sujet excluant nécessairement les autres branches de sujet (en supposant qu'elles sont ramifiées à partir d'une ligne de base commune). Les développeurs ne veulent pas terminer une fonctionnalité pour en démarrer une autre en ayant l'impression que le code qu'ils viennent d'écrire n'est plus là

  4. Comment éviter de créer des conflits de fusion (à cause de la sélection)?

    Ce qui semble être un moyen sûr de créer un conflit de fusion est de choisir entre les branches, elles ne pourront plus jamais être fusionnées? Est-ce que l'application du même commit dans revert (comment faire?) Dans l'une ou l'autre branche pourrait résoudre cette situation? C'est une des raisons pour lesquelles je n'ose pas pousser pour un workflow largement basé sur la fusion.

  5. Comment se décomposer en branches topiques?

    Nous nous rendons compte qu'il serait génial d'assembler une intégration terminée à partir de branches de sujet, mais souvent le travail de nos développeurs n'est pas clairement défini (parfois aussi simple que de "fouiner") et si du code est déjà entré dans un sujet "divers", il ne peut plus être retiré de là, selon la question ci-dessus? Comment travaillez-vous pour définir / approuver / graduer / publier vos branches thématiques?

  6. Des procédures appropriées telles que la révision du code et l'obtention du diplôme seraient bien sûr très intéressantes.

    Mais nous ne pouvons tout simplement pas garder les choses suffisamment intriquées pour gérer cela - des suggestions? branches d'intégration, illustrations?

Voici une liste de questions connexes:

Découvrez également ce que Plastic SCM écrit sur le développement axé sur les tâches , et si Plastic n'est pas votre choix, étudiez le modèle de branchement de nvie et ses scripts de support .

HiQ CJ
la source
2
Hah, merci, en effet ça a ... J'ai en fait lu la plupart de ces trucs :-). C'est quelque chose pour lequel je suis connu - ne pas me contenter de la solution médiocre mais continuer à chercher le parfait. Souvent, c'est une erreur, mais dans ce cas, beaucoup est en jeu et les solutions à portée de main sont tout simplement trop désordonnées ou médiocres que je dois continuer à chercher. J'ai donc décidé d'énumérer tous les problèmes que j'ai avec elle.
HiQ CJ
Le blog Plastic SCM a jeté son opinion dans la discussion, c'est au moins perspicace: codicesoftware.blogspot.com/2010/08/…
HiQ CJ
1
Vous devez être prudent lorsque vous utilisez "merge --no-ff", vérifiez ceci pour quelques mises en garde sandofsky.com/blog/git-workflow.html
Doppelganger
1
@Doppelganger Je serais intéressé par la façon dont spécifiquement --no-ff est censé contribuer au problème décrit dans le lien que vous publiez. Pour moi, le problème décrit est l'échec de la bissect avec les validations de checkpoint et l'échec de git blame pour aider dans ce cas - mais je ne vois pas comment "--no-ff" change quoi que ce soit, au lieu de ne pas l'utiliser. L'auteur se plaint qu'une fusion avec --no-ff ne modifie pas un fichier - mais sans lui, le fichier ne serait pas modifié non plus, vous ne verriez que l'ancien commit de votre historique, non?
codeling
Autre modèle de branchement: modèle cactus barro.github.io/2016/02/… , modèle de ligne principale bitsnbites.eu/a-stable-mainline-branching-model-for-git . Ce modèle à deux branches offre une autre approche que gitflow.
Mathieu Momal

Réponses:

91

La fonctionnalité la plus troublante que les nouveaux développeurs de DVCS doivent réaliser concerne le processus de publication :

  • vous pouvez importer (récupérer / tirer) le repo distant dont vous avez besoin
  • vous pouvez publier (pousser) sur n'importe quel repo (nu) que vous voulez

De là, vous pouvez respecter quelques règles pour faciliter vos questions:

Maintenant:

Workflows / modèles de branchement :

chaque flux de travail est là pour prendre en charge un processus de gestion des versions , et qui est adapté à chaque projet.
Ce que je peux ajouter au flux de travail que vous mentionnez est: chaque développeur ne doit pas créer une branche de fonctionnalité, seulement une branche "dev en cours", car la vérité est: le développeur ne sait souvent pas exactement ce que sa branche va produire: un fonctionnalité, plusieurs (car elle a fini par être trop complexe), aucune (car pas prête à temps pour la sortie), une autre fonctionnalité (parce que celle d'origine avait "morphé"), ...

Seul un «intégrateur» doit établir des branches de fonctionnalités officielles sur un référentiel «central», qui peuvent ensuite être récupérées par les développeurs pour rebaser / fusionner la partie de leur travail qui correspond à cette fonctionnalité.

Fusion vs rebasage (enchevêtrement vs historique séquentiel) :

J'aime ma réponse que vous mentionnez (" Description du flux de travail pour l'utilisation de git pour le développement en interne ")

Je recherche un workflow naturel :

pour les correctifs, il peut aider à associer chaque correctif à un ticket provenant d'un suivi des bogues, ce qui aide le développeur à se souvenir où (c'est-à-dire sur quelle branche, c'est-à-dire une branche dédiée "pour les correctifs") il / elle doit commettre de telles modifications.
Ensuite, les hooks peuvent aider à protéger un dépôt central contre les poussées de corrections de bogues non validées ou de branches à partir desquelles il ne faut pas pousser. (pas de solution spécifique ici, tout cela doit être adapté à votre environnement)

Comment éviter de créer des conflits de fusion (à cause de la sélection)?

Comme l'a déclaré Jakub Narębski dans sa réponse , la cueillette devrait être réservée aux rares situations où elle est requise.
Si votre configuration implique beaucoup de sélection de cerises (c'est-à-dire "ce n'est pas rare"), alors quelque chose ne fonctionne pas.

Serait l'application du même commit dans revert (comment faire cela?)

git revert devrait prendre soin de cela, mais ce n'est pas idéal.

Comment se décomposer en branches topiques?

Tant qu'une branche n'a pas encore été repoussée partout, un développeur doit réorganiser son historique de commits (une fois qu'il / elle voit enfin que le développement prend une forme plus définitive et stable) en:

  • plusieurs branches si nécessaire (une par caractéristique clairement identifiée)
  • un ensemble cohérent de commits dans une branche (voir Trimming Git Checkins )

Des procédures appropriées comme la révision du code et l'obtention du diplôme?

Le repo des branches d'intégration (dans une intégration dédiée) peut aider le développeur à:

  • rebaser son développement au dessus de cette branche d'intégration à distance (pull --rebase)
  • résoudre localement
  • pousser le développement vers ce repo
  • vérifier avec l'intégrateur qui ne se traduit pas par un gâchis;)
VonC
la source
@UncleCJ: comme vous pouvez le voir, ce n'est pas exactement une réponse finale à votre "dernière question";)
VonC
Je comprends, et j'ai aussi un bon sens de l'ironie, c'est ok ;-)
HiQ CJ
3
@UncleCJ en amont est juste l'endroit d'où vous tirez régulièrement, de mon message, où que finissent tous les commits (la version finale ou le tronc dans le langage SVN). En aval, tout le monde est en dessous d'eux. L'envoi de trucs en amont est le processus de fusion dans le référentiel de versions (comme linux-2.6) et en aval les changements à partir de là, ou à partir de votre référentiel, comme le gestionnaire du développement d'une telle fonctionnalité pour vos serviteurs ... I méchante équipe.
2
@UncleCJ: "Je trouve toujours difficile de rogner vos checkins pour obtenir un historique strictement séquentiel": c'est plus facile avec Git1.7 et ses rebase --interactive --autosquashqui déplaceront automatiquement toutes les validations avec le même début d'un autre message de validation. Si ces validations utilisent un numéro de ticket (par exemple), même si les correctifs liés à ce ticket n'ont pas été effectués de manière séquentielle à ce moment-là, l'autosquash permet une réorganisation rapide de ces validations.
VonC
1
@UncleCJ: "histoire strictement séquentielle (est-ce nécessaire ou pas?!)": Pas toujours nécessaire, mais cela permet de garder une trace des dépendances fonctionnelles ( stackoverflow.com/questions/881092/… ) et des conflits sémantiques ( stackoverflow.com/questions / 2514502 /… )
VonC
21

Je pense, et je me trompe peut-être, que l'une des choses les plus mal comprises à propos de git est sa nature distribuée. Cela rend très différent de dire la subversion dans la façon dont vous pouvez travailler, bien que vous puissiez imiter le comportement SVN si vous le souhaitez. Le problème est à peu près n'importe quel workflow, ce qui est génial mais aussi trompeur.

Si j'ai une bonne compréhension du développement du noyau (je vais me concentrer là-dessus), tout le monde a son propre dépôt git pour développer le noyau. Il y a un référentiel, linux-2.6.git, géré par Torvalds, qui sert de référentiel de publication. Les gens clonent d'ici s'ils souhaitent commencer à développer une fonctionnalité contre la branche "release".

D'autres référentiels font un peu de développement. L'idée est de cloner à partir de linux-2.6, de se ramifier autant de fois que vous le souhaitez jusqu'à ce que vous ayez une "nouvelle" fonctionnalité fonctionnelle. Ensuite, lorsque cela est prêt, vous pouvez le mettre à la disposition de quelqu'un considéré comme fiable, qui tirera cette branche de votre référentiel dans la leur et la fusionnera dans le courant dominant. Dans le noyau Linux, cela se produit à plusieurs niveaux (lieutenants de confiance) jusqu'à ce qu'il atteigne linux-2.6.git, auquel cas il devient "le noyau".

Voici maintenant où cela devient déroutant. Les noms de branche n'ont pas du tout besoin d'être cohérents entre les référentiels. Je peux donc git pull origin master:vanilla-codeet obtenir une branche du originmaître de dans une branche de mon référentiel appelée vanilla-code. Pourvu que je sache ce qui se passe, cela n'a pas vraiment d'importance - il est distribué dans le sens où tous les référentiels sont des pairs les uns des autres et pas seulement partagés entre plusieurs ordinateurs comme SVN.

Donc, avec tout cela à l'esprit:

  1. Je pense que c'est à chaque programmeur de faire son branchement. Tout ce dont vous avez besoin est un référentiel central pour gérer les versions, etc. Le tronc pourrait l'être head. Les versions peuvent être des balises ou des branches et les correctifs sont probablement des branches en soi. En fait, je ferais probablement des versions en tant que branches afin que vous puissiez continuer à les patcher.
  2. Je fusionnerais sans rebaser. Si, par exemple, vous prenez un référentiel, le clonez, branchez et faites du développement, puis retirez de votre, originvous devriez, dans votre référentiel, probablement créer une autre branche et fusionner la dernière masteren yourbranchafin que quelqu'un d'autre puisse extraire vos modifications avec le moins d'effort possible. possible. Il y a très rarement un besoin de vraiment rebaser, selon mon expérience.
  3. Je pense qu'il s'agit de comprendre comment Git fonctionne et ce qu'il peut faire. Cela prend du temps et beaucoup de bonne communication - j'ai vraiment commencé à comprendre ce qui se passait quand j'ai commencé à utiliser git avec d'autres développeurs et même maintenant, certaines choses dont je ne suis pas sûr.
  4. Les conflits de fusion sont utiles. Je sais, je sais, vous voulez que tout fonctionne, mais le fait est que le code change et que vous devez fusionner les résultats en quelque chose qui fonctionne. Les conflits de fusion sont en fait juste plus de programmation. Je n'ai jamais trouvé d'explication facile sur ce qu'il faut faire à leur sujet, alors le voici: notez les fichiers qui ont des conflits de fusion, allez les changer pour ce qu'ils devraient être, git add .puis git commit.
  5. Cependant cela convient. Comme je l'ai dit, le référentiel git de chaque utilisateur est le leur et les noms de branche n'ont pas besoin d'être les mêmes . Si vous disposiez d'un référentiel intermédiaire, par exemple, vous pourriez appliquer un schéma de dénomination, mais vous n'en avez pas besoin pour chaque développeur, uniquement dans le référentiel de versions.
  6. Ceci est l'étape de fusion. Vous fusionnez uniquement dans les branches de publication, etc. lorsque vous considérez que le code doit être examiné / passer des tests de qualité.

J'espère que ça aide. Je me rends compte que VonC vient de publier une explication très similaire ... Je ne peux pas taper assez vite!

Modifiez quelques réflexions supplémentaires sur la façon d'utiliser git dans un cadre commercial, car cela semble pertinent pour l'OP dans les commentaires:

  • Le référentiel de versions, nous l'appellerons product.git, est accessible par un certain nombre de programmeurs / techniciens principaux chargés de s'occuper réellement du produit lui-même. Ils sont analogues au rôle des mainteneurs dans OSS.
  • Ces programmeurs dirigent probablement également en partie le développement de nouvelles versions, de sorte qu'ils peuvent également se coder et maintenir des référentiels varios. Ils peuvent gérer des référentiels intermédiaires pour de très nouvelles fonctionnalités et ils peuvent également avoir leurs propres référentiels.
  • En dessous d'eux se trouvent des programmeurs chargés de développer des bits individuels. Par exemple, quelqu'un pourrait être responsable du travail de l'interface utilisateur. Ils gèrent donc le référentiel UI.git.
  • En dessous d'eux sont les programmeurs réels qui développent les fonctionnalités comme leur travail quotidien complet.

Que se passe-t-il alors? Eh bien, tout le monde tire au début de chaque journée de la source "en amont", c'est-à-dire le référentiel des versions (qui contiendra également probablement les derniers éléments du développement des jours précédents). Tout le monde le fait directement. Cela ira sur une branche dans leur référentiel, probablement appelé "maître" ou peut-être si vous m'appelez "dernier". Le programmeur fera alors un peu de travail. Ce travail peut être quelque chose dont ils ne sont pas sûrs, alors ils font une branche, font le travail. Si cela ne fonctionne pas, ils peuvent supprimer la branche et revenir en arrière. Si c'est le cas, ils devront fusionner dans la branche principale sur laquelle ils travaillent actuellement. Nous dirons que c'est un programmeur d'interface utilisateur qui travaille latest-uidonc il le fait git checkout latest-uisuivi pargit merge abc-ui-mywhizzynewfeature. Il dit ensuite à son responsable technique (le responsable de l'interface utilisateur) hé, j'ai terminé une telle tâche, retirez-vous de moi. C'est donc le cas pour l'interface utilisateur git pull user-repo lastest-ui:lastest-ui-suchafeature-abc. Le responsable de l'interface utilisateur le regarde ensuite sur cette branche et dit, en fait, c'est très bien, je vais le fusionner ui-latest. Il pourrait alors dire à tout le monde en dessous de lui de tirer de lui sur leurs ui-latestbranches ou quel que soit le nom qu'ils leur ont donné, et ainsi la fonctionnalité est explorée par les développeurs. Si l'équipe est heureuse, le responsable de l'interface utilisateur peut demander au responsable des tests de se retirer de lui et de fusionner les modifications. Cela se propage à tout le monde (en aval du changement) qui le teste et soumet des rapports de bogues, etc. Enfin, si la fonctionnalité réussit les tests, etc., l'un des principaux responsables techniques pourrait la fusionner dans la copie de travail actuelle du programme, à quel moment toutes les modifications sont ensuite propagées vers le bas. Etc.

Ce n'est pas une façon de travailler "traditionnelle" et est conçu pour être "piloté par les pairs" plutôt que "hiérarchique" comme SVN / CVS. En substance, tout le monde a un accès commit, mais uniquement localement. C'est l'accès au référentiel et au référentiel que vous désignez comme référentiel de version qui vous permet d'utiliser la hiérarchie.


la source
Merci beaucoup pour votre réponse détaillée (et vos votes), je vais la lire encore quelques fois pour en extraire des informations utiles. Cependant, nous sommes une entreprise, pas un comité de développement OSS ;-), et je dois aider mes développeurs avec des directives plus claires que "tripoter comme vous voulez dans votre propre référentiel". Voyons voir où mène ce post, je sens une bonne dynamique, continuez!
HiQ CJ
@VonC Merci. @UncleCJ true, mais vous avez, j'en suis sûr, des gestionnaires de versions, etc. Toute personne ayant accès au référentiel peut faire ces choses. En ce qui concerne le développement, pourquoi ne pas donner aux développeurs la liberté, dans des limites raisonnables, de s'éloigner? À condition que vous ayez un protocole pour accepter les fusions et que vos référentiels centraux soient nommés comme vous le souhaitez, il n'y a pas de problème. Cela dit, un schéma de dénomination commun n'est pas une mauvaise idée. J'ai tendance à utiliser les sous-branches initiales-version-fonctionnalité-pour les branches personnelles et la version pour les branches.
@UncleCJ J'ai ajouté un exemple sur la façon dont cela pourrait fonctionner dans une entreprise. Ce sont essentiellement les rôles OSS remplacés par des gestionnaires, mais vous avez compris. Il a l'avantage supplémentaire par rapport à SVN que vos développeurs peuvent également travailler hors ligne (ils n'ont besoin que du net pour tirer / pousser) et je pense qu'il facilite le test des fonctionnalités, si vous l'implémentez bien.
Wow, c'est en fait un excellent exemple, nous pouvons commencer à utiliser quelque chose comme ça pour la remise des diplômes. Je ne voulais pas tellement dire que comme nous ne faisons pas d'OSS, tout le monde doit être réglementé, nous sommes en fait une équipe assez petite et plate, mais nous devons essayer de collaborer efficacement sur un calendrier serré et aussi d'apprendre en équipe . C'est pourquoi je pose ici ces questions stupides pour que je puisse aider le reste de l'équipe plus tard :-). J'ai également réalisé à partir de #git qu'une ligne de base mal définie combinée à une pression pour raccourcir les délais de livraison nous fait trébucher ... sera de retour plus tard.
HiQ CJ
C'est assez juste - j'y suis allé récemment, c'est exactement comment j'ai pris cet exemple, en l'essayant et en échouant beaucoup ... et en m'adaptant également aux méthodes de travail de certains projets OSS. Je suppose que le vrai problème, c'est que la façon dont vous vous branchez et où se trouvent vos référentiels n'a pas d'importance ... vous pouvez les définir comme vous le souhaitez, ce qui m'a vraiment choqué! Mais cela vous permet de faire des choses intéressantes. Quoi qu'il en soit, bonne chance et amusez-vous!
9

Un modèle que j'ai utilisé avec de bons résultats est le suivant:

Un dépôt "béni" que tout le monde pousse et tire vers / depuis, essentiellement une topologie client-serveur.

Il n'y a pas de branche principale, donc aucun développeur ne peut pousser de code dans la «ligne principale».

Tous les développements se produisent sur des branches thématiques. Nous avons des noms d'espaces de noms pour détecter facilement qui en est responsable: jn / newFeature ou jn / issue-1234

Il y a aussi un mappage quasi-direct entre les branches et les cartes kanban / scrum sur le tableau blanc.

Pour libérer une branche, elle est poussée vers le dépôt béni et la carte kanban est déplacée pour être prête à être examinée.

Ensuite, si la branche est acceptée par la revue, elle est candidate à une libération.

Une version se produit lorsqu'un ensemble de branches acceptées est fusionné et étiqueté avec un numéro de version.

En poussant la nouvelle étiquette vers le dépôt béni, il y a une nouvelle base possible pour de nouvelles fonctionnalités.

Pour éviter les conflits de fusion, les développeurs sont priés de mettre à jour (fusionner) leurs branches non publiées vers la dernière balise de version.

John Nilsson
la source
2

Personnellement, j'essaie de ne garder que du code prêt à être publié dans la branche master.

Lorsque je travaille sur une nouvelle fonctionnalité ou un nouveau bug, je le fais dans une branche. Je fais aussi des tests unitaires dans la branche. Si tout fonctionne correctement, alors seulement je fusionne / rebase dans le maître.

J'essaie également d'utiliser des conventions de dénomination de branche communes, telles que:

  • bugfix / recursive_loop
  • correction de bogue / sql_timeout
  • feature / new_layout
  • fonctionnalité / recherche_améliorée
xero
la source