Project
Trunk Based Development

Trunk Based Development

Trunk based development refers to a style of managing version control where there is predominantly only one branch. There is only one source of truth. This may sound like a step back from the popularized systems like "gitflow" or "gitlab flow" but it is actually much simpler and much more powerful.

Approaches like "gitflow" and "gitlab flow" originate from trying to apply experiences from other version control systems to git and from trying to manage a large project without modern CI automation tools like GitLab.

Trunk based development, when supported by tooling of GitLab, is the workflow that you get when you take the best of all other approaches. Trunk based development is one of the most important prerequisites to implementing efficient continuous delivery.

Problems with traditional workflows

There are two main version control strategies that have been popularized over the years.

  • Developing on main: under this model developers work directly on main and push their changes to main. This may sound a lot like trunk based development but lacks important elements like automated testing before merge and code review.
  • GitFlow Workflow: This model has been popularized in 2010 by Vincent Driessen and has been used by many projects since then.
  • GitLab Flow Workflow: This model has been developed at gitlab as a simplification of the gitflow model.

Developing on main

In this pattern, developers work on main branch, committing code at least once a day. Branches are avoided and large changes are broken down into smaller pieces that are added to main while making sure that main branch is always in working state.

However, the fact that developers push directly to main does not scale. It is too easy to break the main branch and because there is no quality gateway that is built into the process, development is actually hampered by the fact that too many defects make it into the main branch unchecked.

While the main idea of developing on main is highly desirable, in trunk based development we take this idea several steps further and implement both code review process and quality gateways as well.

GitFlow Workflow

The gitflow model is one of the first branching models that became extremely popular. Part of the reason for it’s popularity could have been that git made branching and merging extremely effortless compared to older version control systems and people were so excited about this new feature that they started using it extensively (too much perhaps?)

gitflow model

Key characteristics of the gitflow model include:

  • You use feature branches branched off from develop branch to build features in isolation from each other.

  • You use develop branch as the "integration" branch where features are then integrated by merging feature branches into the develop branch.

  • The main branch always contains highly stable code - the code that is deployed to production.

  • Releases are branched off from develop, stabilized and then merged into main.

While this model looks really good on paper, it is very difficult to implement properly without creating a mess. It is simply too complex. The complexity makes it difficult to manage. Multiple sources of truth and long lived branches (such as the develop branch) cause difficulties when making a release.

GitLab Flow Workflow

GitLab started with the gitflow approach and then realized it’s problems and simplified it considerably. This is how the gitlab flow branching model was created.

gitlab flow model

This model has several simplifications over the original model:

  • There is only one trunk (main branch) where all changes are integrated through merges.

  • Developers still create feature branches and work on features there.

  • Releases are branched off from the main integration branch and then stabilized

  • Bug fixes are first integrated into main and then "cherry picked" (or back ported) to the release branches.

This model still suffers from several problems:

  • Trunk is not linear history (there are merge commits) making the history difficult to manage.

  • The model does not define criteria for allowing something to be merged / released, format for commit messages etc.

  • The model does not define workflow for code review.

Note that these models continuously improve and today the GitLab flow model is much more in line with best practices than it was before.

Trunk Based Development

Trunk based development takes the best parts of all of the existing approaches and combines it into a cohesive whole. A process that is both easy to implement on an individual level and also a process that scales to large teams.

trunk based development

Under this new model, the git workflow is as follows:

  • git fetch origin: get latest update from shared repository

  • git checkout -b <ticket id>_short_name origin/main: checkout a feature branch and implement tasks in the ticket

  • tig or git commit: quick way to stage partial or full changes

  • git fetch origin/main: get latest changes from others again so we can update our feature branch

  • git rebase -i origin/main: if there have been many changes then I mark all of my intermediate fixes as "fixup" so that they get collapsed into one commit (easier to fix git conflicts that way)

  • git push origin <feature branch> --force: force push but ONLY the feature branch (remember, it’s a throwaway branch always)

When a merge request is created for merging the new feature branch into main, the gitlab system will run all the pipeline jobs that you have defined for verifying that the code is in good shape and only after that the merge request can be approved and merged.

Under trunk based development, the merge request as the smallest unit of work that gets merged into main repository. Using merge requests instead of individual commits gives us advantages in terms of how many checks we can enforce automatically before something is allowed to be merged. With individual commits we don’t have the same possibility to run checks and deny something from being added to the main branch if it doesn't fulfill quality requirements.

Releases

Releases under trunk based development usually happen directly on the main trunk and are characterized by tagging the main trunk with a release version tag and publishing a release to a package repository.

Branches can be used as well if releases need to be maintained over a long time. In such a scenario, branches are snapshots of the code taken when trunk is tagged with a release. This branch then lives on for as long as that release needs to be maintained.

Any fixes and changes done to the release branches are usually merged into trunk to keep trunk up to date. Any changes done in trunk that also affect older releases are typically cherry picked into releases where they are relevant. Trunk always represents the state of the software as it is at any given time.

Code reviews are built into the workflow

Once a merge request is created, others can look at the code and review it. In GitLab it is possible to comment on individual lines of code and even suggest changes.

The process is as follows:

  • Work starts: developer starts working on an issue

  • Feature branch: developer creates a feature branch based on main git branch -b my_feature origin/main

  • Merge request: developer creates a merge request (in draft state).

  • Work continues: developer adds changes to the branch and pushes it regularly to the server (which also updates the changes visible in the merge request).

  • Ready for review: once merge request is ready for review developer removes the draft status and invites reviewers to review it.

  • Additional work: problems discovered during review are fixed and pipelines are made to pass.

  • Approval: project maintainer approves the merge request.

  • Changes are merged: changes are squashed and added to main branch. This has the effect of merging the changes to main even though no merge commit is created.

Tools

In trunk based development following tools are very useful to make the process work:

  • GitLab: installable as a docker image and free to use. Very easy to install.

  • Gitlab CI: you must make sure you run tests and all checks on the code automatically. Use the .gitlab-ci.yml file in your repository to configure this.

  • Code formatting: use tools like clang-format and autopep8 for enforcing formatting. Almost all langauges have automated formatting tools. Integrate these into your CI pipelines.

  • Code linting: use tools like mypy, pylint and clang-tidy to automatically check the code for semantic errors. These tools are able to find possible out of bounds errors, wrong type usage and many other problems. Every language has a linter, even bash (shellcheck).

  • Codeowners: use this file CODEOWNERS in your repository to configure reviewers and approvers for merge requests based on files that are being changed. This is a very good way to optimize the assignment of code reviewers.

Best practices

  • Automate everything: make sure that when automated checks pass, you can have high confidence that if you deploy the application it will work perfectly.

  • Lightweight code review: make the code review process lightweight. Automate things like spell checking so that code review doesn't need to point out spelling errors.

  • Synchronous code reviews: when speed is important, make the code reviews synchronous where developers sit together and resolve problems directly instead of waiting for each other's comments on merge requests.

Martin SchröderMartin Schröder
16 years  of experience

About the author

Martin is a full-stack expert in embedded systems, data science, firmware development, TDD, BDD, and DevOps. Martin serves as owner and co-founder of Swedish Embedded Consulting.

Expertise

Embedded Firmware
Zephyr RTOS
Scrum
Continuous Delivery

Contact Martin

By completing signup, you are agreeing to Swedish Embedded's Terms of Service and Privacy Policy and that Swedish Embedded may use the supplied information to contact you until you choose to opt out.

Confirm your contact information

Thank you!

An email has been sent to you with a link to book a short call where we can discuss your project further. If you have any further questions, please send an email to info@swedishembedded.com