Brancing & Merging - A Developers Guide (3 Part Series)
I discovered the release flow methodology after working with Git Flow for a number of years. I loved Git Flow, it’s simplicity was amazing.
That said, I am a firm believer in always trying new things and continually striving to improve.
Release flow is Microsoft’s model of branching and merging. It is how they manage almost all of their production level deployments. They also use Azure Dev Ops internally, and as I am a huge Dev Ops advocate it seemed a much nicer fit.
They actually use Azure Dev Ops and Release Flow, to deploy changes to Azure Dev Ops. Mind = Blown
There are some Microsoft links at the bottom of this article with more details, but I’ll cover the broad concepts here.
Whenever a developer wants to make a change, bug fix or feature, they branch from master. These ‘topic’ branches are encouraged to be short-lived and committed early. Feature flags are a huge part of this model.
Once a developer has finished working on a change, they merge back to master. Disabling any potentially breaking functionality with feature flags.
When a release is ready, a new branch is created with a relevant name (release/220.127.116.11). Any final changes are made to documentation or version numbers and then a production build is started from this release branch.
The management and number of different branches differ from Git Flow in that there is only one branch with an infinite lifetime. That being master
All new development work, be it features or hotfixes, begins as a branch from master. Master should always contain the most up to date code, including any newly developed features.
This is where the use of feature flags comes into its own. If you are a developer working on a new feature and you want to control the deployment you’d wrap the code in feature flags. That way, you can slowly control the rollout of the new feature to select users/servers.
Another important point regarding master is how code is merged back in. It should be done in a very controller way.
For me, that is branch policies and pull requests. All merges to master need to be done through a pull request that is reviewed by at least one person. It also requires that a build runs and completed successfully.
One of the great features of Azure Dev Ops is it allows you to run a build pipeline and only complete the pull request if the build succeeds. If the build fails, notifications are sent out and the pull request fails. It’s a fantastic control for allowing developers to get real-time feedback on their changes.
I’ve grouped both features and hotfixes into one section, as the management of these branches works in the same way.
If you need to make a change to a codebase, the first thing you would do is create a new branch from master. As with release flow, naming conventions vary massively. I tend to stick with the good old fashioned ‘feature/’ and ‘hotfix/’.
If I was working in a large development team, I would use usernames as well. Giving ‘jeasthamdev/feature/featurename’.
Keep feature and hotfix branches short lived. Commit often, commit early and use feature flags to keep control
Once ready to move a change back to master, a new pull request is created. When approved, the code is merged back into master.
An important point on urgent hotfixes. If a bug is found in a current live release that needs to be fixed before the next planned release, the pull request should be ‘cherry-picked’ into the release branch. But more on that later…
To blow the Azure Dev Ops trumpet again, it provides a fantastic UI to make this process extremely easy. After completing a pull request, you can click a cherry-pick button and a new branch is created to merge your pull request in with the selected branch. Could it possibly be easier?
When it comes to creating a release, a new branch is created from the master. This is where a consistent naming convention has to be agreed upon within your team. Senseless naming of release branches would cause A LOT of confusion.
I tend to keep it simple, and go with ‘release/’.
Once the release branch has been created, any final changes should be made. For me, this normally includes updating documentation and checking version numbers are correct.
Once happy, a CI/CD pipeline is kicked off to move this release branch into production.
So there we have the overarching structure of the release flow model, without further ado. Let’s jump into some code:
For this short tutorial, I’m going to use the same code base as from the Git Flow article. However, to show the full power of this process, I am going to use Azure Dev Ops. The repo can be found here https://dev.azure.com/jeastham1993/blog-release-flow.
I’m going to cover the configuration of branch policies and automatic builds in a later post, so I will skip over that quite quickly now.
I have a new feature request for my super useless API, which is to add a new feature that simply returns ‘Hello Earth’.
To start with, I create a new branch. That can be done either through the web UI or from a terminal window. To keep this as close to Git Flow as possible, I’ll use the terminal.
git checkout -b feature/addhelloearth
Once the new branch has been created locally, I can go ahead and make the change.
After completing the changes, and any local testing (as you can imagine there are TONNES of testing required for this codebase) I run a commit and push.
git add server.js
git commit -m "[FEATURE] Add hello earth endpoint"
git push --set-upstream origin feature/addhelloearth
If the branch had been created in Azure Dev Ops and pulled down, the last step would simply be ‘git push‘.
Now that the code is committed, I have two branches in Azure Dev Ops
When navigating the repo in the UI, I also receive a handy little message informing me about my outstanding change.
And that is exactly what I am going to do. I create the pull request and the new feature is merged into master.
My updated feature has passed through both QA and staging and I am now ready to release it to the world.
For that, I create a new branch from master named release/version_number, make changes to my documentation and push it.
git checkout -b release/1.1.0
git add README.md
git commit -m "[INTERNAL] Update documentation
git push --set-upstream origin release/1.1.0
Ordinarily, I would run this step in the actual Azure Dev Ops UI. For comparison to Git Flow, I have kept it all in a terminal window.
Once pushed, I have a production release pipeline configured within Azure Dev Ops (again, one for a later post). The pipeline watches for any changes to a branch named release/* and pushes them to production.
Our code is in production, and everyone is happy. Until the team who requested the new feature realized they requested the wrong thing. They actually wanted to say hello to the world, not to the earth.
Luckily, with the release flow model, this proves to be really simple. So what do we do?
Starting from the master branch (because all branches come from master), I would run:
git checkout -b hotfix/correctingfeaturethestupidteamaskedfor
I always tend to run a git pull command first to make sure everything I have locally is up to date.
I’d then make the fix in the new hotfix branch and push that back to my repo.
The branch would be automatically tested and then merged into master, this is great. It means the fix is now there for any new work added, so is guaranteed never to be missed in a later release.
Obviously, the master branch may now contain tonnes of new features that aren’t ready to be made live. This is where feature flags have a massive role. However, using the Azure Dev Ops UI there is a fantastic way to merge select changes.
After merging my hotfix branch into master, I receive this handy little message giving me an option to Cherry-pick.
On clicking the cherry-pick button I can quickly select which branch I want to merge this one change into.
This is entirely possible using standard git commands, but having such an intuitive interface within Azure Dev Ops is a great experience.
As the production pipeline is set up to run as soon as a change is made to a release/* branch, it just releases instantly.
That my friends is release flow! Of the two models, release flow fits a lot better with the way my company works. But there are both pros and cons to using Git Flow or Release Flow.
Throw into the mix the other methodologies for managing a git repo, and there’s plenty of choices.
What I’ve tried to cover with these two articles, is that having a strategy of some kind is important.
Don’t set up a version control system and think you are done because your code is controlled.
Don’t think that you are immune from easy rollbacks and simple changes because your code is controlled.
Use git to its full potential. Branch, merge and enjoy the robustness that comes with that.