Feature-based development (commonly known as “GitFlow”) is a git branching model that has been widely used since it was introduced in 2010. It’s an excellent choice for mission-critical software, since teams get really familiar with features and spend extensive time iterating and reviewing them. However, GitFlow isn’t considered best-practice for most types of software development. Here’s why you might want to migrate to trunk-based development, and how you can take those first steps.
What exactly is GitFlow?
GitFlow, or feature-based development, is a complex but common version control pattern. It restricts feature development to long-lived branches, each of which will be in use until a feature is entirely complete. GitFlow is often used for projects that have scheduled releases. A GitFlow integration is typically a major task, since developers will have to get their new feature up-to-date with the main branch, and resolve any merge conflicts (which are almost inevitable in a long-lived branch with a large git diff). It’s fallen out of favor because features get stale quickly, and merges typically come with a higher cognitive load, thanks to the sheer volume of code changes in every branch.
Can I do true CI/CD with GitFlow?
While you can and absolutely should use a CI/CD pipeline with GitFlow development, you won’t be doing CI/CD (the practice). CI/CD, as a practice, means pushing/testing/integrating small commits into main on upwards of a daily basis by means of automation.
With GitFlow, you are likely running tests against new commits and automating other aspects of the build pipeline, but you’re doing this in larger chunks and at a slower cadence.
Interestingly, teams tend to start looking towards trunk-based development when they want to improve their CI/CD. TBD is a prerequisite for CI/CD, since CI/CD is essentially applied trunk-based development.
What is trunk-based development?
Trunk-based development is a rapid git development model in which commits are pushed/integrated directly into the trunk (or main branch). TBD foregoes branches entirely, and doesn’t traditionally use PRs/MRs.
One of TBD’s typical constraints is that each developer should integrate at least one commit every 24 hours. Developing with TBD helps developers move faster since their commits are smaller, therefore there’s less cognitive load expended while writing/reviewing code. By virtue of commits being so small, the chance of a merge conflict is really low.
Obviously, going from a branching model to TBD is a massive undertaking, and getting there takes a combination of solid automation practices and teamwork.
Are there alternatives to trunk-based development?
The lack of branches and PRs/MRs are deterrents for many teams that otherwise would thrive with trunk-based development. Sometimes it can be really tricky to write the perfect standalone commit, and many developers might do better writing a handful of complementary commits. Also, a PR/MR serves as a good “gate” between your code changes and production.
There’s a good intermediate between trunk-based development and GitFlow called “GitHub flow”. Essentially, it’s trunk-based development but with really short-lived branches and PRs. GitHub uses it in-house for a few of their domains.
GitLab flow is also a good alternative to GitFlow. It isn’t too similar to trunk-based development, but we’d be remiss to skip it. While it’s simpler than GitFlow, it’s still much more complex than GitHub Flow; it incorporates production and stable branches, in addition to main. GitLab flow is really solid for issue tracking, and makes it easier to implement release tracking.
Three starters for trunk-based development
Trunk-based development isn’t something that you can just start doing. It takes a combination of changes to your people, process, and technology, and you’ll need to make adjustments before/during/after the commit stage. Here are three ways you can set yourself up for success.
1. People!
In TBD, solving for people is 70-80% of the battle. As a manager, you’ll have to help your team change their development patterns.
First and foremost, TBD is best done with atomic commits, or small, fully standalone commits. This makes rollbacks easy (simply revert the commit and nothing will break), and helps teams break down tickets into smaller, bite-sized tasks.
It doesn’t matter how quickly you write code if your teammates aren’t quick in their code reviews. They should be ready and willing to review a commit as soon as it’s tested, so that you can maintain your cadence.
TBD falls apart without proper communication and teamwork, and these changes will take some practice before things go smoothly.
2. Testing
Testing is an integral component of TBD, and must be up-to-spec before you adopt TBD patterns. Strong test automation enables you to keep pace with daily trunk integrations, and to focus more on development and less on quality checks.
Testing and team practices go hand-in-hand. Tests should be written by the author of every corresponding commit, and they should be written immediately after the commit. Nobody understands the intended behavior of a code change more clearly than its author, which is why they’ll be most effective at writing tests/looking for edge cases (and this should challenge them to re-evaluate how a code change affects the code base).
With these habits, your team should have enough test automation in place to get quick feedback and trust every new commit. Code reviewers should jump in only after the pipeline is green, so that they’re reviewing for style/architecture and not for “bugginess”. End-to-end, integration, and unit tests should simulate a large amount of production scenarios, so that there are few surprises after a push to trunk.
3. Observability
Observability is insurance against your test suite: o11y and testing are two sides of the same coin. It’s inevitable that bugs/regressions will seep into production. That’s why you should have strong monitoring and alerting in place, so if something goes wrong, you can revert your (atomic) commit immediately, and go back to the drawing board.
There are obviously things that go wrong that can’t be caught by traditional test cases, especially when dealing with your app at scale. Observability helps keep you aware of these. Instead of babysitting every new deployment, your alerts will let you know when something spikes or fails and you can remediate.
Production-like test environments on every code change
When adopting trunk-based development, your infra needs to be up to the task. To get extensive testing on every commit, you’ll need a test environment with real services and similar data to what you use in production. Shipyard creates full-stack ephemeral environments that respond to GitOps events, so you can test against every commit, preview your UI/UX, and get manual review, entirely on demand. Try it free for 30 days, and see how much faster your team can deploy.