Git ou SVN : Comment Nuance Healthcare a opté pour un modèle de branching Git ?

Matt Shelton
Matt Shelton
Retour à la liste

Cet article est un billet d'invité de Matt Shelton de Nuance Healthcare. Il s'agit du premier d'une série consacrée à la migration de son équipe de Subversion vers Git, aux raisons qui ont motivé cette migration et aux problèmes rencontrés. Matt a également évoqué ce sujet à l'Atlassian Summit 2015. Cette série développera tous les points qu'il n'a pas pu aborder lors de sa présentation de 30 minutes, avec davantage de contexte.


My team is in the healthcare division at Nuance. We're geographically-distributed between a couple of offices and homes on the East Cast of the US, and in an office in Pune. We develop Java web services to deliver NLP[1] solutions to the healthcare market.

Pour la plupart, nos clients sont des éditeurs de logiciels dans le domaine de la santé (y compris nous-mêmes) comme des fournisseurs de dossiers médicaux électroniques et des sociétés spécialisées dans l'analytique médicale. Nous commercialisons également certains produits auprès des hôpitaux et des utilisateurs finaux des applications, qui vont des médecins au personnel médical chargé de la facturation. Les gens « normaux » comme vous et moi ne touchons jamais le logiciel créé par mon équipe.

Our team has been around the block a few times with Application Lifecycle Management product combinations. We started life with a mix of Rally Enterprise and Seapine TestTrack Pro, did about 14 months of hard labor with Rational Team Concert, and eventually migrated fully to the Atlassian stack (Jira, Confluence, Bamboo, Crucible, Bitbucket and Hipchat). Historically we used Subversion 1.4/1.5 an our SCM with a quasi-normal trunk/branches/tags structure. We have been using maven since forever manage our build projects and dependencies, and switched from Jenkins to Bamboo for continuous integration (CI) a while ago in order to make use of tighter integrations with Jira and its flexible build and deploy agent capabilities. Everything we use (now) is behind the firewall for reasons[2].

Git ou SVN ?

We support roughly ten individual products across four product families, and the owners of these products are always battling for prioritization and timing. It’s nice to have our work be in high demand, and this is by no means a complaint, but it also necessitates cutting releases at a weird cadence and needing to change directions in the middle of a sprint[3].

Par moments, notre processus de développement nous semblait prohibitif. Mon équipe avait souvent la discussion suivante :

Me: We need to release 1.8.0 to QA now for regression testing so that Customer foo can go to beta next week. Dev: I'm still working on ABC-123 which is in trunk. It's not done yet. Me: Foo doesn't need ABC-123. We could put it in the next release. Dev: But I've been working on it for weeks. There's no clear spot to branch from to cut a release. Me: Well, you'll need to pull out all of your changes by hand. You have about two hours or QA can't finish in time.

I know, I sound like a jerk! I never meant to be, and of course I'm exaggerating a bit to make a point, but we really did have to figure out how to get code that was in one place out of that place temporarily so that we could cut a release, and then put it right back for the next release[4]. And this happened all the time.

Now, I know some of you are thinking "Subversion supports branches, Matt...". It absolutely does, and we used them on occasion with SVN 1.4 and 1.5. Branching is a fine operation in SVN; merging can be a pain in the ass. As SVN has matured, it has gotten better, for sure. But we knew there were better options out there for us, so when the question of SCN or git arose, we set out to get Git.

Remarque : nous avons brièvement examiné la dernière version de SVN (1.8 à l'époque) pour vérifier si elle permettait de résoudre nos problèmes, mais nous n'avons pas été complètement satisfaits. L'un de nos groupes de pairs possède une installation Perforce importante, ce qui répondait bien à la plupart de nos besoins, mais je ne pouvais tout simplement pas avaliser les coûts de licence. Nous nous sommes également intéressés à Mercurial pendant un temps, mais au final, l'expérience de l'équipe existante avec Git a suffi pour nous convaincre que c'était le bon choix à faire.

I won't sugar-coat this: Atlassian's tools really favor teams who use git. Other SCMs work fine; our SVN integration was sufficient in that it linked us to where a given user story's changes were made. The integration capabilities for teams who use Bitbucket Server[5] instead, however, are both stronger and more natural-feeling in the Jira Software interface and development experience - ditto with Bamboo.

Knowing this, and having seen some very stellar demos at Summit 2013, I strongly encouraged the team to go for it. Nobody objected, and we already had the licenses in place to make change.

Sélection d'un modèle de branching Git

After deciding to make this change, the first challenge we had was deciding what Git branching model to implement for our team. Atlassian's Git microsite as well as this great presentation from Summit 2013 explain in greater detail what a branching model is. The short version is that it describes how you will use branches in git to power your development workflow.

In SVN, we had a model for branching I'll call "make one when you realize you - OMG! - need one":

  • The newest code is in trunk. Releases from trunk will be numbered A.B.0-{build}.
  • If a fix is required to a trunk-based release (e.g. we have a bug in 1.2.0-64), a branch is created and from there we will release A.B.C-{build} releases, where C increments after every release that goes out the door. These branches may never exist for a given A.B and we could even have more than one.
  • Nous taguons également chaque livraison dans un répertoire dédié.

An Aside About Versions Many years ago, when I was just cutting my teeth on managing a development team, our release engineer had a system of versioning that was... how shall I say?... really unintuitive. Essentially, every release was a patch on the previous one (A.B.n), with no respect for the place from which the patch originated. Figuring out where something came from and, in almost all cases, the release order, required you to look at svn log. We printed the tree on a wall for reference. In addition, our public-facing release numbers tend to be things like 3.0, 3.1, 3.5, 4.0, or essentially something a customer might expect. Remember, though that my team builds web services not a boxed product. Our APIs are a contract. A few years ago I made the executive that my team's builds, and therefore its releases, would adhere to Semantic Versioning rules. I've' had to stand my ground a few times with upper management, but now it is understood why the rules are what they are, and we haven't looked back. Partners appreciate that sort of clarity.

I mentioned a problem earlier wherein we'd be working on a release (let's say 1.2.0) and we'd have a feature still in progress as we approached a release date. We would need to pull that code out, cut our release, branch to branches/1.2.1 and then merge that code back in, hoping nobody had a hard drive crash in the meantime[6].

Removing a whole feature by itself from a shared trunk is a pain. Everyone hated life when they had to do that. svn blame can be useful, as can a strong diff tool, but it’s still annoying to work with. I often took it personally, feeling that my bad planning had led to us not having all of our ducks in a row before it was time to be done with a release[7]. My team dealt with this for long enough.

Parfois, nous avons surcorrigé le code pour éviter de nous embêter et nous avons demandé aux développeurs de rester les bras croisés pendant quelques jours (une sorte de gel de code virtuel si vous voulez), le but étant de ne pas polluer le trunk avant une livraison.

Nous savions donc que nous avions besoin, au minimum, de branches de fonctionnalité. Un modèle de branching Git simple s'applique : une branche master pour ce qui est en production et des branches de fonctionnalité pour les fonctionnalités, les bugs, etc. Les équipes doivent gérer le merge afin de s'assurer que ce qui sort de la branche master est bien ce qui est censé se trouver dans la livraison. Auparavant, nous avions un résultat similaire avec une isolation de fonctionnalité relativement meilleure, mais nous voulions être libres de faire ce que nous voulions.

In our environment, we often need to keep a few versions in production, and may need to fix defects in a release that is 2-3 minor revisions older than what we are working on right now. So, in addition to feature branches, we also needed some sort of release branch or similar that would let us fix issues from previous releases. The Atlassian Bitbucket Server team does this. They make fixes in long-running support branches, and then merge them up the branch stream so that a fix makes it in to all of the support streams.

Son modèle semblait vraiment bon, c'est pourquoi nous l'avons testé avec des prototypes pour voir s'il était adapté à nos besoins. Pour eux, l'« application géniale » est celle qui fait un merge d'une correction en continu dans leur branche develop. Ce concept était sympa. Mais, à chaque fois que nous l'avons essayé, nous avons rencontré un problème avec nos dépendances Maven. De plus, nous ne pouvions généralement pas être sûrs que nous souhaiterions un merge direct du travail d'une version à une autre. Dans certains cas, nous avions besoin d'implémenter la même correction de manière légèrement différente entre les versions. Un merge direct n'était donc pas possible.

A few of the members of the team strongly favored a variation of this model known as "git-flow". Git-flow is a set of branch naming conventions and merge guidelines, authored by Vincent Driessen. This felt very natural to the team, and we liked the structure since it eliminated many of the questions around "what do I do when we need to do x?". The answers were generally very obvious. Rather than explaining what git-flow is, you can read more about it in Atlassian's tutorial.

The only gap left for us with git-flow was what to do about those long-running releases in production. Since master keeps moving forward, we couldn't use the git-flow hotfix workflow for a bug fix from a previous release. On the other hand, we didn't always want a support branch.

Généralement, une branche hotfix corrigeant uniquement la dernière livraison en production doit suffire, la branche support n'étant là que lorsque nous avons besoin de revenir plus en arrière ou lorsque nous devons maintenir la compatibilité pour une raison quelconque. Nous avons étudié ce cas plus en détail et nous avons déterminé des critères pour l'utilisation d'une branche support plutôt que d'une branche hotfix et d'une mise à niveau mineure de la livraison :

  1. Ce code ne peut pas être trivialement réincorporé dans le développement.
  2. Le partenaire/client ne peut gérer un changement d'interface survenant lors de la dernière livraison.
  3. There is an internal dependency which cannot be changed.[8]

Both git-flow extension packages[9] provide support for the support branch concept, which isn't part of the original draft of git-flow, but has become popular enough to warrant inclusion.

Git-flow offered a workflow we liked, with the tooling support we needed. In the next post I'll go into what happened when we actually tried using it in a POC project we used to represent our development process. It was... a learning experience!

[1]: Natural Language Processing. WE CAN READ YOUR THOUGHTS. (No. Not really.)

[2]: There is a lot that is attractive about Atlassian's cloud offerings, but we need to keep our fingers wrapped tightly around our servers and data for the time being. While we don't personally need to do much with PHI data, our software does and it's important to keep it as secure as possible.

[3]: Shhhh... don't tell Ken Schwaber.

[4]: Which might have only been a few days later anyway.

[5]: Formerly known as Stash. Hello, Atlassian Fall Rebranding!

[6]: I know we could always pull it out of the previous commit. I was kidding.

[7]: This wasn't usually the case - generally it was because someone else's timeframe moved up and we had to react quickly.

[8]: This is one of those things I can't get into on my own blog. Just trust me. "Reasons".

[9]: The original package by Vincent Driessen isn't being maintained any longer. A new fork , however, is regularly updated.

Prêt à découvrir Git ?

Essayez ce tutoriel interactif.

Démarrez maintenant