web-dev-qa-db-fra.com

Quels modèles de branchement Git fonctionnent pour vous?

Notre société utilise actuellement un modèle de branchement trunk/release/hotfixes simple et aimerait obtenir des conseils sur les modèles de branchement les mieux adaptés à votre entreprise ou à votre processus de développement.

  1. Flux de travail/modèles de branchement

    Vous trouverez ci-dessous les trois descriptions principales de ce que j'ai vu, mais elles se contredisent partiellement ou ne vont pas assez loin pour résoudre les problèmes que nous avons rencontrés par la suite (comme décrit ci-dessous). Ainsi, notre équipe n’a pas jusqu’à présent trouvé de solutions par défaut. Tu fais quelque chose de mieux?

  2. Fusion vs rebasement (historique enchevêtrée vs séquentielle)

    Faut-il pull --rebase ou attendre la fusion sur la ligne principale jusqu'à la fin de votre tâche? Personnellement, je suis enclin à la fusion, car cela préserve une illustration visuelle de la base sur laquelle une tâche a été commencée et terminée, et je préfère même merge --no-ff à cette fin. Il a cependant d'autres inconvénients. En outre, beaucoup n’ont pas compris 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 le maître dans la branche de sujet).

  3. Je recherche un flux de travail 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 précédentes devrait bien sûr être suffisamment basé 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 soit intégré au 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é (même pire, fusionné ou quelque chose basé sur celui-ci), l'option restante est la sélection des priorités, avec ses périls associés. Quelles règles simples comme celles-ci utilisez-vous? La maladresse d'une branche de sujet exclut nécessairement les autres branches de sujet (en supposant qu'elles soient issues d'une ligne de base commune). Les développeurs ne veulent pas finir une fonctionnalité pour en commencer une autre, car ils ont l'impression que le code qu'ils ont écrit n'est plus là

  4. Comment éviter de créer des conflits de fusion (en raison d'une sélection sélective)?

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

  5. Comment se décomposer en branches topiques?

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

  6. Des procédures appropriées telles que la révision de code et la remise des diplômes seraient bien sûr agréables.

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

Vous trouverez ci-dessous une liste de questions connexes:

Vérifiez également ce que Plastic SCM écrit sur développement piloté par une tâche , et si Plastic n’est pas votre choix, étudiez modèle de branchement de nvie et his scripts de support .

367
HiQ CJ

La caractéristique 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 (Push) vers n'importe quel dépôt (nu) que vous voulez

À partir de là, vous pouvez respecter quelques règles pour rendre vos questions plus faciles:

Maintenant:

Flux de travail/modèles de branchement :

chaque flux de travail est là pour prend en charge un processus de gestion des versions , et il est adapté à chaque projet.
Ce que je peux ajouter au flux de travail que vous avez mentionné est le suivant: chaque développeur ne doit pas créer de branche de fonctionnalité, mais seulement une branche de "développeur en cours", car la vérité est que le développeur ne sait souvent pas quoi branch produira: une fonctionnalité, plusieurs (car elle a fini par être une fonctionnalité trop complexe), aucune (car elle n’est pas prête à la sortie), une autre caractéristique (parce que la version originale était "transformée"), ...

Seul un "intégrateur" devrait établir des branches de caractéristiques officielles sur un dépôt "central", que les développeurs peuvent ensuite extraire pour redéfinir/fusionner la partie de leur travail qui correspond à cette caractéristique.

Fusion/rebasement (historique enchevêtrée vs séquentielle) :

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

Je recherche un flux de travail naturel :

pour les correctifs, il peut être utile d’associer chaque correctif à un ticket issu d’un suivi de bogues, ce qui aide le développeur à se rappeler où (c’est-à-dire sur quelle branche, c’est-à-dire une branche dédiée "pour les correctifs"), il/elle doit valider ces modifications.
Ensuite, les points d'ancrage peuvent aider à protéger un dépôt central contre les envois 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 (en raison d'une sélection sélective)?

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

Est-ce que appliquer le même commit à revenir (comment faire cela?)

git revert devrait s'en occuper, mais ce n'est pas idéal.

Comment se décomposer en branches topiques?

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

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

Des procédures appropriées comme la révision de code et la remise des diplômes?

Les succursales d'intégration (dans un rapport d'intégration dédié) peuvent aider le développeur à:

  • rebasonner son développement sur cette branche d'intégration à distance (pull --rebase)
  • résoudre localement
  • Poussez le développement à ce repo
  • vérifiez auprès de l'intégrateur que cela ne crée pas de désordre;)
89
VonC

Je pense, et je peux me tromper, que l’un des aspects les plus mal compris de git est sa nature distribuée. Il est donc très différent de dire Subversion de la manière dont vous pouvez travailler, même si vous pouvez imiter le comportement de SVN si vous le souhaitez. Le problème est quasiment n'importe quel flux de travail, ce qui est excellent mais également trompeur.

Si j'ai bien compris le développement du noyau (je vais me concentrer sur cela), tout le monde a son propre référentiel git pour développer le noyau. Il existe un référentiel, linux-2.6.git, géré par Torvalds, qui fait office de référentiel de publication. Les personnes clonent à partir d’ici si elles souhaitent commencer à développer une fonctionnalité contre la branche "release".

D'autres dépôts font du développement. L'idée est de cloner à partir de linux-2.6, en le faisant autant de fois que vous le souhaitez, jusqu'à ce que vous disposiez d'une "nouvelle" fonctionnalité. Ensuite, lorsque cela sera prêt, vous pourrez le rendre disponible à une personne considérée comme digne de confiance, qui extraira cette branche de votre référentiel dans le sien et la fusionnera dans le grand public. Dans le noyau Linux, cela se produit à plusieurs niveaux (lieutenants de confiance) jusqu'à atteindre linux-2.6.git, auquel cas il devient "le noyau".

Maintenant, voici où cela devient confus. Les noms de branches n'ont pas besoin d'être cohérents d'un dépôt à l'autre. Je peux donc git pull Origin master:Vanilla-code et obtenir une branche du maître de Origin dans une branche de mon référentiel appelée Vanilla-code. Dans la mesure où je sais ce qui se passe, cela n'a pas d'importance - il est distribué dans le sens où tous les référentiels sont homologues les uns des autres et ne sont pas simplement partagés sur plusieurs ordinateurs tels que SVN.

Donc, avec tout cela à l'esprit:

  1. Je pense que c'est à chaque programmeur de décider comment ils vont créer leurs branches. Tout ce dont vous avez besoin est un référentiel central pour gérer les versions, etc. Le tronc peut être head. Les versions peuvent être des balises ou des branches et les correctifs logiciels sont probablement des branches en elles-mêmes. En fait, je ferais probablement des communiqués sous forme de branches afin que vous puissiez continuer à les corriger.
  2. Je voudrais fusionner et pas rebase. Si, par exemple, vous prenez un référentiel, clonez-le, branchez et effectuez quelques dev, puis extrayez-vous de votre Origin, vous devriez, dans votre référentiel, probablement créer une autre branche et fusionner le dernier master dans yourbranch afin que quelqu'un d'autre puisse extraire vos modifications avec le moins d'effort possible. D'après mon expérience, il est très rarement nécessaire de vraiment rebaser.
  3. Je pense que c'est un cas de compréhension du fonctionnement de Git et de ce qu'il peut faire. Cela prend un certain temps et beaucoup de bonne communication - je n'ai vraiment commencé à comprendre ce qui se passait que lorsque j'ai commencé à utiliser git avec d'autres développeurs et, même maintenant, des 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 pour obtenir quelque chose qui fonctionne. Les conflits de fusion ne sont en réalité que davantage de programmation. Je n’ai jamais trouvé une explication facile à ce sujet, alors la voici: notez les fichiers qui ont des conflits de fusion, changez-les en ce qu’ils devraient être, git add . puis git commit .
  5. Cependant cela convient. Comme je l'ai dit, chaque référentiel git des utilisateurs est leur propre base de jeu et les noms de branches n'ont pas besoin d'être identiques . Si vous avez un référentiel de transfert, par exemple, vous pouvez appliquer un schéma de nommage, mais vous n'avez pas besoin de le faire pour chaque développeur, uniquement dans le référentiel de version.
  6. C'est l'étape de la fusion. Vous ne fusionnez dans les branches de publication, etc. que lorsque vous considérez que le code est révisé/satisfait aux tests de qualité.

J'espère que ça aide. Je réalise que VonC vient de publier une explication très similaire ... Je ne sais pas taper assez vite!

Edit Quelques réflexions supplémentaires sur l'utilisation de git dans un contexte commercial, car cela semble pertinent pour le PO d'après les commentaires:

  • Le référentiel de versions, appelé product.git, est accessible à un certain nombre de programmeurs/responsables techniques expérimentés chargés de veiller au produit lui-même. Ils sont analogues au rôle des mainteneurs dans les logiciels libres.
  • Ces programmeurs sont probablement aussi en partie responsables du développement de nouvelles versions, ils peuvent donc aussi se coder eux-mêmes et gérer des référentiels varios. Ils pourraient gérer les référentiels de transfert pour de nouvelles fonctionnalités et disposer de leurs propres référentiels.
  • En dessous se trouvent des programmeurs chargés de développer des bits individuels. Par exemple, une personne peut être responsable du travail de l'interface utilisateur. Ils gèrent donc le référentiel UI.git.
  • Au-dessous d’eux figurent les programmeurs qui développent les fonctionnalités dans leur travail quotidien.

Alors qu'est-ce qui se passe? Tout le monde tire au début de chaque journée de la source "en amont", c’est-à-dire du référentiel de versions (qui contiendra probablement aussi les derniers documents des dernières journées de développement). Tout le monde le fait, directement. Cela ira sur une branche de leur référentiel, probablement appelée "maître" ou peut-être si vous m'appelez "dernière". Le programmeur va ensuite faire quelques travaux. Ce travail peut être quelque chose dont ils ne sont pas sûrs, alors ils créent une branche, font le travail. Si cela ne fonctionne pas, ils peuvent supprimer la branche et revenir en arrière. Si tel 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 travaillant sur latest-ui alors il fait git checkout latest-ui suivi de git merge abc-ui-mywhizzynewfeature. Il dit ensuite à son responsable technique (le responsable de l'interface utilisateur) hé, j'ai terminé une telle tâche, tire-moi. Donc, le plomb de l'interface utilisateur fait git pull user-repo lastest-ui:lastest-ui-suchafeature-abc. L'interface utilisateur principale l'examine ensuite sur cette branche et dit, en fait, c'est très bien, je vais le fusionner dans ui-latest. Il pourrait alors demander à tous ceux qui se trouvent en dessous de lui de tirer de lui sur leurs ui-latest branches ou le nom qu’ils leur ont donné, pour que la fonctionnalité soit explorée par les développeurs. Si l'équipe est satisfaite, le responsable de l'interface utilisateur peut demander au responsable des tests de le retirer et de fusionner les modifications. Cela se propage à tous ceux (en aval du changement) qui le teste et soumet les rapports de bogues, etc. Enfin, si la fonctionnalité passe les tests, etc., l'un des principaux responsables techniques peut le fusionner dans la copie de travail actuelle du programme, auquel cas tous les changements sont ensuite propagés vers le bas. Etc.

Ce n'est pas un mode de travail "traditionnel" et est conçu pour être "piloté par les pairs" plutôt que "hiérarchique" comme SVN/CVS. Essentiellement, tout le monde a accès au commit, mais seulement localement. C'est l'accès au référentiel et le référentiel que vous désignez comme référentiel d'édition qui vous permet d'utiliser la hiérarchie.

21
user257111

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

Un repo "béni" tout le monde pousse et tire vers/depuis, en gros une topologie client-serveur.

Il n'y a pas de branche maître, aucun développeur ne peut donc insérer de code dans "mainline".

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

Il existe également une correspondance presque 1 pour 1 entre les branches et les cartes kanban/scrum sur le tableau blanc.

Pour relâcher une branche, elle est poussée vers le dépôt béni et la carte kanban est transférée sur prête pour vérification.

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

Une libération survient lorsqu'un ensemble de branches acceptées est fusionné et étiqueté avec un numéro de version.

En poussant la nouvelle balise vers le dépôt béni, il existe 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 avec la dernière balise de publication.

9
John Nilsson

Personnellement, j'essaie de ne garder que le code prêt pour la publication dans la branche principale.

Lorsque je travaille sur une nouvelle fonctionnalité ou une correction de bug, je le fais dans une branche. J'ai aussi des tests unitaires dans la branche. Si tout se passe bien, alors seulement je fusionne/rebase en maître.

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

  • correction de bug/recursive_loop
  • correction de bug/sql_timeout
  • feature/new_layout
  • fonctionnalité/Enhanced_search
2
xero