Go with the (git)flow, or die debating
Tags: git, devops, github
Published: 2023-09-11 08:12:23

We all version our codebase using one of the many version control systems (VCS) on the market. Since I started working for [wellD](https://www.welld.ch/it/index.html?utm_source=Medium&utm_medium=ContentMarketing&utm_content=Gowiththegit), we have changed three of them.

**In the beginning, we were using _CVS_**, but given its inability to be atomic–in an *all-or-nothing* sense–it really wasn’t fun when something got stuck halfway through. Let’s not even mention its performances.
 **Our next step was then to switch to _SVN_**; we **chose not to go for *git* because it was too *complex*! As a result, merging two branches would always give us a headache.
**Finally, it was _git_-time**, which positively disrupted the way our developers’ team worked.

Unlike the first two VCSs, however, *git* forces users to define **shared methodologies** to use the system.

In this respect, one of the first challenges we faced was to agree on a shared **branching strategy**. To make our decision, we considered the following criteria: easy-to-integrate **Continuous Integration** (CI), **frequent releases**, and step-by-step **code review**.

## Branching strategy

Keeping in mind the criteria we just mentioned, here is an **overview of the branching strategies** we, directly and indirectly, experimented with.

### Anarchy strategy

AKA “no-strategy.” This model empowers each developer to create branches **without following any convention ** whatsoever with respect to a branch’s duration, name, and content.

*Ideally*, this enables a quick kickoff and an independent development. But *alas*, a much more tangible result is that it doesn’t take long for the situation to become **impossible to manage**.

By adopting this strategy, the team will have to spend time trying to identify the active development branch, on which branch they should develop code, on which branch(es) a specific feature is located, or which branch should be pushed to production.

### Git Flow

For over a year, we used *git-flow*, which provided us with an **organized**, **methodical**, and **structured** alternative, and a CLI that allowed us to avoid naming convention issues.

![GitFlow CLI](https://cdn-images-1.medium.com/max/2000/1*aPXZJ1SUhjuB8KyCgueWQg.png)

The idea behind *git-flow* is pretty simple:

* The master branch includes all the tags for all released versions;

* The develop branch is used for ongoing development processes;

* Feature branches are dedicated to the new features that are being developed;

* Release branches are for software versions that are candidates for release;

* Hotfix branches are destined to bug fixes flagged by the production team.

![GitFlow schema](https://cdn-images-1.medium.com/max/2000/1*XpAbI8DN8h25wKmanaTIYA.png)

The biggest problem with **GitFlow** is its **complexity**. The whole development process doesn’t occur on the master branch–i.e. the default branch for many tools–rather on develop, while master is only used to store releases.

This kind of approach actually prevents developers from **code reviewing** pending merge requests (MR) on the master branch–which are required since this branch is protected–as these will include content developed in weeks, if not months. It is, however, possible to send MRs from feature branches to the develop branch. Yet this only depends on the developer’s commitment, because MRs are not required for the develop branch since it is not protected, or at least it is not so by default.

One of the greatest issues we had was **to correct bugs in versions preceding the latest release**. Let’s say we released version `2.X` of a software and the client flags us an issue in version `1.Z`. The wisest choice would be to go on the master branch and create a support branch for tag `1.Z` to fix the bug. But what should we do after the bug fix? From which branch should our fix be released: the `support` branch, the `master` branch, or something else? Into what should we merge our fix? Should it be merged in the `master` branch or perhaps in the `develop` branch? Or, rather, should we just leave the `support` branch we created forever unmerged?

The release process in GitFlow can get really tough. Here are the steps involved:

* Use the command `git flow release start <VERSION_NUMBER>` to create the release branch from develop;

* Update your **codebase** (**changelog**, project version, readme, etc.;)

* Wait for the CI to green-light the creation of an MR on `master`;

* Merge the release branch into master with the command `git flow release finish <VERSION_NUMBER>`. Once this step is done, the release branch will be merged into `master` and `develop`, and a `tag` will be created for the release commit. After that, we will be redirected to `develop`;

* **push** `master`, `develop`, and the `tag` (note: `git push --tags`)

P.S.: First, update the project version on develop for the next iteration, then **push**.

Sometimes this process can be overkill, and experience has taught me that making a mistake is quite easy.

### GitHub Flow

GitHub Flow relies on a **clean** and **simple** structure, with only 2 kinds of branches: the `master` branch and the `feature` branches. A developer creates a branch from the repository on which the new **feature** is developed. Once done, an MR (with code review) is sent to master. To update an MR, you simply need to push content on your branch, and when the MR is ready this will be merged in master. After that, the feature branch is removed.

![GitHub flow](https://cdn-images-1.medium.com/max/2000/1*gr9HebeZzALsZKQ8_Pt1qA.png)

This branching strategy, however, is based on **2 strong assumptions**:

 1. Developed contents can be pushed to production at any time, which is not always true. For many of our clients, we have a set time frame on a certain date to push a new software version to production.

 2. Clients always install the last version of our app, so there is no need to **support** and **fix bugs** for older releases. 🤔

### Gitlab Flow 🚀

Starting from GitHub Flow, a new strategy came up, one that provides **a branch for each environment**. Let’s say we have a **staging** environment, a Quality Assurance (**QA**) environment, and a **Prod** environment. Each of them is updated automatically using a CI script pointing to the relevant branch.

![GitLab Flow environment branches](https://cdn-images-1.medium.com/max/2000/1*1bWdU3Wv2Qoi-vQ-CFt2RA.png)

Like this, we can benefit from small and exact MRs to master, which can be subject to code review. When we’re ready, we can push changes to the QA environment (sending MRs from the master to the pre-production branch) and then to the Prod environment (sending MRs from the pre-production to the production branch).
Thanks to this workflow, we can rest assured that all commits are tested in all environments.

Sometimes, there is the need to keep developing multiple versions of a software, in which case **Release Branches** come in handy.

![GitLab Flow - Release branches](https://cdn-images-1.medium.com/max/2000/1*iZhT_0XqYv1aytooZ9nUjA.png)

In this case, each branch corresponds to one version of our software (the image above depicts a *minor* version.) In order to avoid making **hotfixes** on multiple branches, the creation of the release branch (the *stable* branch in the picture) is delayed for as long as possible.

When an anomaly occurs in our software, the fix is made on a `feature` branch, which is then merged into the `master` branch. After that, we cherry-pick the commit on the release branch. This technique, known as **Upstream First**, is used so that the developer doesn’t forget to merge a hotfix into master, preventing the problem from occurring in future releases.

### Conclusion 🤓

One of the principles of **[Lean](https://leankit.com/learn/lean/lean-methodology/)** that I appreciate the most is continuous improvement, a concept that is perfectly depicted by this anecdote:
>  There was once the owner of a big American company, who decided to adopt **Lean** to improve his production line. A couple of months after introducing it, he invited the owner of a Japanese factory–where Lean had been implemented since day one–to visit his factory.
 On the day of the meeting, the American gave his Japanese guest a tour of his factory, showing him the improvements that had been made thanks to Lean. The Japanese watched but didn’t make any comments.
 At the end of the tour, the host asked his guest: “What do you think of the way we reorganized our factory by following your guidelines? Have we managed to embrace Lean fully?”
 The Japanese guest answered: “I do not know that. I was not here yesterday!”

This is just to say that, starting from CVS, in time we have embraced **git** and **Gitlab Flow**, which currently seems to suit our development cycle well enough. Nonetheless, we are always open to experiment with and potentially adopt any tool or strategy that improves our developers’ team life.

### References 🔗

* [https://docs.gitlab.com/ee/workflow/gitlab_flow.html](https://docs.gitlab.com/ee/workflow/gitlab_flow.html)

* [https://datasift.github.io/gitflow/IntroducingGitFlow.html](https://datasift.github.io/gitflow/IntroducingGitFlow.html)

* [https://danielkummer.github.io/git-flow-cheatsheet/](https://danielkummer.github.io/git-flow-cheatsheet/)

* GitLab Flow example: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)

* Upstream first: [https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first](https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first)

— 
[Matteo Codogno](https://twitter.com/teo1690), Technical Leader @[WellD](https://www.welld.ch/it/index.html?utm_source=Medium&utm_medium=ContentMarketing&utm_content=Gowiththegit)