How can I leverage Octopus Deploy with the GitFlow branching strategy?

GitFlow is a popular git branching strategy. The TL;DR; of the that linked to document (grossly oversimplified) is:

  • Developers develop on feature branches
  • Developers merge into the dev branch
  • Once a release is ready, a release branch is created
  • Any bug fixes for that release are made on a bugfix branch from that release branch

Imagine you had 5 environments. At any given point you could expect to see the following versions:

  • Development: 2020.3.1 (latest changes from dev)
  • QA: 2020.2.3 (QA is testing the latest changes from the previous sprint)
  • UAT: 2020.1.5 (Customers are verifying changes about to go to production)
  • Stage: 2019.12.2 (Staging is a copy of prod)
  • Production: 2019.12.2

Some use cases to think about:

  • Development might push up to QA, but that is very unlikely
  • Typically QA and UAT are typically testing the same version (2020.2.x).
  • Occasionally, a release gets held up in UAT due to a customer concern, which requires extra bug fixes
  • A bug is found in production which requires a hotfix. It shouldn’t step all over what is being tested in QA or UAT

What are some recommendations for using Octopus Deploy with GitFlow?

The recommended approach is to leverage lifecycles and channels.

To start, we will need 5 environments listed in the question.

With those environments, we will create four lifecycles:

Before proceeding, let’s pause to discuss the use cases for each lifecycle

  • Sprint Lifecycle: to be used during a sprint (or while work is being done for a release). Developer does a PR from a feature branch, it gets approved, and the build server deploys to Development. The majority of the time, the deployments only go to development.
  • Test to Prod Lifecycle: to be used after a sprint when QA is verifying the code. A release branch is created. The build server sees that and deploys right to Test. Ideally the final build from this branch is pushed through all environments to Production.
  • UAT to Prod Lifecycle: to be used when a release is held up in UAT. The build server will need a bit of smarts to see this release should go to UAT first and not to Test. If a release is held up in UAT it will need a path to production once all concerns are addressed.
  • Hotfix Lifecycle: to be used when a production bug is found. When the code is checked in for the hotfix it should be deployed directly to staging to be verified prior to production.

Now that we have our lifecycles, we will need to create channels for each project following this branching strategy.

As an extra layer of protection, each channel will have version rules. Default is using the sprint lifecycle, and it has the latest and greatest code, so releases from the 2020.3.x release is allowed. QA only allows releases in the 2020.2.x releases. UAT only allows releases in 2020.1.x. Meanwhile production has 2019.12.x releases.

The version rules aren’t required. They are there to help prevent code from being deployed via the wrong channel. Having them does add a bit of complexity as you will have to update the version rules after each release branch is created.

The question now becomes, how does a build server know which channel select when creating the release? That will depend entirely on your business rules. What I would recommend is using the Octopus API to check the last release number for each environment. Here is an example on how to do that. Once you know the release number per environment you can infer which channel you need to deploy to.

If you would like to see this sample in action, please go to: https://samples.octopus.app/app#/Spaces-25 and sign in as a guest.

Hi @Bob_Walker, great write up thanks!

We use the GitFlow branching strategy and I’ve been thinking about simplifying our release projects with channels, however I am worried that for a hotfix there exists a possibly for the release process to have been changed, for changes made in development, that would break a hotfix e.g. command line arguments for a process get completely changed.

Is this an issue and are there any suggestions on how to best handle it? It’s not the kind of scenario that would happen often, but when trying to release a hotfix I wouldn’t want it to be held up while having to work back through some release process changes.

An approach I came up with to avoid the issue would be to first clone any steps that need editing and then have the edited step only run for the development environment and the unedited step run for the staging and production environments.

Hmmmm, that is an interesting question. It does come up from time to time. If it is just new steps, I’d say scope the steps to run on the specific channels. For example, you add a new step for what is in dev, then scope that step to the dev channel. When it is time to promote then scope that step to the next channel and so on. If you’re not making a lot of changes, hopefully that isn’t a terrible experience.

For variables or step changes, I’d clone the step or variable. Scope the old variable/step to the release channel, and the new variable/step to all the other channels.

As I type this, this isn’t a great experience, it is something I hope we can solve in upcoming releases.