Deploy Inc.

Branching Strategy

How to ensure similar branching strategy across project groups and simplify feature selection for a release

This article is to be used as a guideline for developers on how to work with git in large scale projects, with multiple environments and developers. It is also a guideline for server and CI tools configuration. It is by no means a comprehensive “one size fits all” guide, but it’s something we’ve found works best for us. Our main priority was to define branching strategy to allow us to selectively include features into a release, while keeping development flow as simple as possible.

There are a few things to keep in mind when using this branching strategy:

  • Features should be self-sufficient – all code for a single feature needs to be in that feature branch, including latest fixes, database code, etc.
  • Environment branches are for building code on separate environments. Never merge one environment branch into another.
  • Development (dev) environment is used for prototyping and (developer) testing during the development phase. QA starts writing test cases in this phase. Merge your feature/* branches into develop as you like (for example: when you’d like to test part of your feature on remote server to make sure your code works there as well).
  • QA branch is for building the QA (or "UAT") environment and should contain developer-tested features, aka "ready for QA". Note: Do developer testing on dev, never on QA.

Main Branches

Repo should have 3 main branches, used for developing and releasing an application.
  1. master
    • Contains: Production-ready code
    • Builds: production
  2. qa
    • Contains: Code ready for testing
    • Builds: qa
  3. develop
    • Contains: Code in development
    • Builds: development
When code is ready for production release, it must be merged from the release branch into the master branch and tagged with the version number. More about this in the Release Procedure section below.

Summary
Do the coding on the feature/* branch.
This ensures separation of different features and helps with code/repo organization.
It also allows for feature deployment when it’s ready, on the appropriate environment, rather than having to include something just because it’s on an env branch.
In addition, this keeps features atomic and (at least somewhat) self-sufficient parts of the project.

Always use feature/* branch for development.

After you're done, merge into the develop branch and push your code.

Try to keep feature/* branches only on your local environment. Most of the time, there's no need to push them to origin, unless multiple people are working on a single feature.

Supporting Branches

Supporting branches have 3 categories:
  1. Feature branch
    • Must branch from: master
    • Must merge into: develop or release/*
    • Naming: feature/* (feature/ /something will work) . The version is the planned version. Eg. if currently 4.5.0 and you're developing version for 4.6.0, put 4.6.0
Feature branches, sometimes called topic branches, are used to develop new features for an upcoming or distant future release. When starting the development of a feature, the target release in which this feature will be incorporated may well be unknown at that point. The essence of a feature branch is that it exists as long as the feature is in development, but will eventually be merged into develop (if the feature will definitely be added to the upcoming release), or it will be discarded (in the case of a disappointing experiment).

Feature branches typically exist in developer repos only, not in origin, unless multiple developers work on a single feature.

Why do feature/* branches originate from master?

The reason why feature/* branches are branched out of master is to make it easier to "pick" features which will be integrated into the release.

Develop is used to build the dev server, and it may sometimes use experimental features or features that are not supposed to be released for longer periods of time. Branching from master ensures that the feature is integration-ready when completed.

  1. Release branch (see "Release Procedure" below)

    • Must branch from: master
    • Must merge into: qa and master
    • Naming: release/version (eg. version release/4.1.0)
    This is the integration branch. It is used to "simulate" a production push. When you’re preparing for a production push (usually after the 1st week of a sprint) you create a release/ branch and integrate features from feature/* branches. Before merging into master for a production push, this branch needs to be merged into the qa branch. After that, the QA team tests on the QA environment, and bugs are fixed on the feature/ branches. These changes are merged back into the release branch, then go back to QA. Finally, after testing is done, the release branch is merged into master.
  2. Hotfix branch

    • Must branch from: master
    • Must merge into: master and develop
    • Naming: hotfix/version/something (eg. hotfix/4.1.1/something)

Release Procedure

When development is complete, and features are ready to be tested on QA, create a release branch.

Steps to follow:

  • From the master branch, create a new branch called "release/x.y.z", where x.y.z is the actual version of the application.
    • For the Laravel framework, the version number is defined under app/config/production/app.php as a variable.
    • Application version number should follow Semantic Versioning 2.0.0 (ref: https://semver.org).
  • Increase version number in application! On the backend side, increase the version number to match the version in the branch name. Note: this could be done automatically via shell script, run by Jenkins. Make sure to tag the merge commit with the appropriate version, using the server syntax defined in the link below. Jenkins should always change the application version according to the version tag of the current commit (or the merge commit that you’re building) - ie. if you tagged the merge commit on master with “4.5.13”, your application version property needs to be “4.5.13”.
  • If the previous version for release was 4.1.0, then this version should be 4.2.0. The last number is always "saved" for hotfixes (please see the versioning standards linked above)
  • During testing on QA, bugs for features might be found. Fix these bugs on feature branches, then merge those feature branches onto develop and into the release branch.
  • When ready, merge the release branch into master and do a production build.
  • Always put a TAG ON MERGE COMMIT when it's created in the master branch. The tag should contain the version number.
  • After the build is complete, dev, qa and production environments should be synced.
    • Merge release branch back into Dev and QA
    • Restore database from production

Hotfix Procedure

When code is released, issues might be present on the production environment. If this is the case, then a Hotfix branch must be created. Try to avoid hotfix patches. If you're patching an existing feature, and that feature does not have a feature/ branch, create a feature/ branch instead of doing a patch. Hotfix branches are to be created only when you need to do a production build mid-sprint (ie. you found a major issue with your latest production build and you need to restore application functionality that was affected). Steps to follow:
  1. Modify code to apply the hotfix
  2. Increase version number in application! Look at the release procedure if you’re unsure how to do this. The version should be the same as in the branch name (following the example above, version should be “4.5.1”)
  3. Merge hotfix branch into master, tagging the merge commit in master with a new tag containing the new version number (following the example from above, the tag should be “4.5.1”)
  4. Merge hotfix branch into develop, qa and release! This is to prevent the bug from reoccurring in the following release and to fix all environments.
This strategy is inspired by: http://nvie.com/posts/a-successful-git-branching-model/
Back to blog