Git makes it easier than ever before to branch work, rewrite history, and merge/rebase from one branch to another, but the result can be a kind of branch chaos. The need to take an official release from some authoritative source ultimately collides with that chaos and makes Git hard to live with. The Git-flow model, proposed some years ago, solves that problem by defining structure and process.
Git-flow defines a hierarchy of branches and a protocol for merging code, which includes tagging important milestones along the way. Through these mechanisms, Git-flow lets devops teams receive work from multiple development teams and produce a release when (most) distributed version control systems lack any conception of a central or privileged server.
However, this overlooks a number of issues and limitations, which the remainder of this article will detail. I’ll discuss the limitations posed by Git (even with Git-flow) for many use cases and explain why other approaches offer a better overall solution for continuous delivery (CD) practices.
To begin, here are four salient issues and limitations from which Git with Git-flow still suffers:
- Git-flow is better suited to a traditional release program than CD
- Git-flow imposes a high knowledge burden with a fragile process
- Git-flow’s process destroys history, which is unacceptable in many cases
- Git itself has significant limitations that aren’t easily overcome
Separating the continuous from the delivery
Regarding the first point, Git-flow defines separate master branches for development and release, under which are supporting branches for features, releases, and hot fixes. This leaves developers free to do as they wish in their local repos (with the usual caveats about rebase and forced pushes) while providing official destinations for finished work. Developers get the “Wild West” freedom they love, and devops gets the structure they need.
The problem is that this is a step backward from CD, which is all about ensuring that every new incremental bit of work that passes various testing, validation, verification, and other processes is immediately deployable. By focusing so heavily on building well-defined releases only after work has been delivered to the proper branches, it misses the point of CD altogether. This is precisely why GitHub doesn’t use the Git-flow model. To quote Scott Chacon from GitHub:
So, why don’t we use git-flow at GitHub? Well, the main issue is that we deploy all the time. The git-flow process is designed largely around the “release.” We don’t really have “releases” because we deploy to production every day -- often several times a day.
High complexity means easy mistakes
While Git-flow’s model indeed works, adapting the old ways of Git to the new ways of devops comes at the cost of a high knowledge burden. Git is a powerful tool, and using it well requires climbing a pretty significant learning curve. Git-flow adds a second curve with two master branches, three types of supporting branches, and a very specific sequence of commands that must be executed for different cases for everything to work properly.
Worse, not only does every developer have to know the complex Git-flow model, but any failure to follow it properly can cause significant confusion. Forgetting to use the flag for no-fast-forward-merge during a commit obscures which commits comprise a feature. Forgetting to increment version numbers, forgetting to tag properly, and so forth can cause other problems. In short, the model is complex and fragile; it’s non-trivial to adhere to it and too easy to make mistakes.
This is precisely why there is a Git-flow library of extensions for Git. But these extensions are themselves complicated enough to warrant another long, technical blog post explaining how to use them properly. The more complex a thing is, the easier it is to get it wrong -- even for people as smart as the typical developer. That’s a big factor to consider when choosing your development tools and workflows.
Destroying history isn’t always an option
Third, Git-flow’s suggested approach, which the Git-flow extensions enforce, is to delete feature and hotfix branches once their work has been delivered to the appropriate destinations. This is fine for a lot of use-cases, but not every project can tolerate this approach.
For example, the medical industry operates under strict, legal requirements to ensure that every commit is preserved in perpetuity, and that every release can be tied back to every line of code and data that went into its production. Any process whatsoever that fundamentally destroys or rewrites history is simply unacceptable. Many other industries have similar concerns.
Limitations of Git
And, of course, it bears to mention that Git itself brings significant limitations to the table. The plethora of “Git management” solutions for the enterprise are aimed at addressing exactly those. It is well known, for example, that Git does not handle large files or large numbers of files very well.
These limitations drive the phenomenon of “Git sprawl.” That is, because repositories become slow to use and work with as they grow beyond a certain size, a common “solution” is simply to spread work out into multiple repos. It’s not uncommon for large projects using Git to require dozens, hundreds, or even thousands of repositories simply to maintain acceptable performance.
No matter how you define branching structures and protocols, you can’t escape the underlying limitations of the tool itself. To be fair, Git works nicely for a wide variety of projects, and upon those projects Git-flow can impose welcome structure. But once your projects grow large or you want to move toward CD, Git and Git-flow are simply sub-optimal.
Bringing everyone together
Let’s briefly reframe the original problem to illustrate why a better choice is necessary. Prior to the rise of CD, product development was far more segregated. Developers tossed work over a veritable wall to QA, QA tossed work over a similar wall to pre-production, and the IT guys were on the hook to keep everything up and running as an overworked fourth party.
Here’s the hard truth: CD tears down those walls. CD requires close cooperation so that new work triggers automated builds, runs unit and other tests, and ultimately produces installers or pushes files directly to servers. CD tears down the walls because it forces developers, QA, devops, IT, and others to work together to build and maintain unified, automated pipelines.
Git is a great tool, but it was written by a developer for developers, and developers are only one piece of the puzzle. Adding Git-flow makes devops happier at the cost of some burdens on developers, but this is still an incomplete solution. QA and IT aren’t even considered; they (and other stakeholders) have needs, too. Therefore, if you’re going to do CD well, your development tools and processes must bring everyone together with a single source of truth.
What is therefore needed is a solution that will empower contributors by letting them use the tools they already know and love. Developers should be able to use distributed version control features to work disconnected, branch locally, and share their work only when ready. Plug-ins should be available for major development environments to simplify the daily grind.
And perhaps more importantly, a solution is required that doesn’t leave devops, QA, IT, or anyone else out in the cold. Devops teams need features to automate the flow of code and integrate processes with other tools. QA needs to keep their tests and assets in the same place. It’s best to use tools that can keep build artifacts, installers, and even complete virtual machine images in the same place. IT needs a solution that stays up and running no matter what, one that makes it easy to synchronize work from teams across the world. And management requires both easy access to analytics data and a level of security that lets them sleep easy at night. Leaving valuable IP at risk simply isn’t an option.
In the final analysis, the end goal for CD is to deliver better products faster and more cheaply. Git-flow imposes badly needed order on what can otherwise be branching chaos with Git by itself. But it’s not well suited to CD for a variety of reasons, and it isn’t a good fit for many projects and industries. There are a number of other approaches and solutions that better cover the variety of use cases and address the needs of all the relevant stakeholders more fully.
John Williston is a veteran software developer for Windows, .NET, and the Web. He is currently product marketing manager at Perforce Software.
This story, "Improving on Git-flow for continuous delivery" was originally published by InfoWorld.