When it comes to Branching and Merging strategies, the internet is full of examples and “best practices”. I personally don’t believe in a best practice, because that’s usually subjective. I’d rather talk about a proven practice.
We will start our branching strategy from the work item we are working on. This ensures traceability is baked into the rest of the process, and ensure that we are working on producing value (technical or functional).
Let’s consider the following work item.
We will create a topic branch, signaling the start of development activities on the work item:
I am placing all the topics under a folder, and naming the branch using the work item id. This allows anyone looking at the branch separately to easily know which work item it is for.
At any time during your development cycle you might have several ongoing topics. These topics should be short lived to avoid complex merge conflicts scenarios.
You can read more about topics branches here: https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows
What we would want to do next to have all these topics branches trigger a build whenever any commit is done for them.
In VSTS, there is a nice feature that allows a build to be triggered by many branches for instance:
Hence with one build definition we can continuously build all the ongoing topics and generate their build artifacts in an organized way:
Testing in Isolation
The topic builds should trigger a release pipeline into environments where the main goal is to validate the work item in isolation from the rest of the ongoing work items.
You should be using as many environments as you deem necessary to validate the code quality, the functionality, the performance, the security and its impact on the overall required infrastructure. If you’re thinking that this would require way too many environments. You are correct, however in a world where cloud is more ubiquitous (Public, Private or Hybrid) and knowing we have now techniques allowing us to create environments on the fly, use them and dispose them once we’re done testing. This should be a no issue.
Once validation is done for your work item, it’s time for you to merge your changes back into the master branch. You will do that using a pull request.
The pull request will show the team responsible for merging the changes into main, what files changed or were added and what work item they are related for. They can comment on your changes, or request additional changes before they approve the merge. Note that in many cases, you are part of that same team. You shouldn’t be however approving your own changes. However, it is very important not to think about this step as a gate but rather collaboration step. Everybody owns the code:
You should have branch policies on your master branch that ensure that pull requests are required for changes to be merged:
Once your pull request is approved, it will trigger a build from the master branch, which itself should trigger a release pipeline allowing your team to integrate your latest work item with others. You should validate the integration of these functionalities and their impact on the health of the application and its infrastructure before releasing it to production:
Once everything is validated, you should be able to deploy the changes to your pre-prod environment and consequently to your production environment. However, achieving continuous delivery requires way more than the ability to deploy continuously. This is where ideas such as “Feature Flags”, “Kill Switches” and “Testing in Production” will help you to increasingly raising your maturity until you can continuously get value in the hands on your customers.
In summary, this is what your Branching CI/CD strategy would look like: