The generally accepted best practice for managing branches and releases in Git is to release from the Main/Master branch.
That strategy is great for simple and/or smaller projects (Microservices
and simple applications). However, for more complex and/or monolithic
applications, this strategy can create some issues.
There are often
scenarios where multiple feature branches are in progress
simultaneously. These branches may be released together or
independently. Additionally, there may be bug fix branches interspersed with the feature branches. Each release to production must pass a full round of automated unit testing and User Acceptance
Testing (UAT) before deployment.
Some questions may be:
- Does testing occur against Main/Master? Or does it occur against the Feature branch?
- If a Feature branch is tested, where do you deploy from? Do you perform a
Pull Request to Main/Master and release from there? If so, won't you be
releasing technically "untested" code?
- How do you test multiple Feature branches and Bug Fix branches simultaneously? Do you merge them all to Main/Master and test from there?
- Where is the"golden copy" of the
application? As in, is there a branch that represents the currently
deployed application or are tags in Git sufficient to mark each release?
Microsoft has a great article on Git branching: Adopt a Git branching strategy.
Combining Microsoft's recommendations with real world experience for complex application development, using a Release branch strategy is generally a good solution.
The strategy is to create a Release branch that has all of the desired features and/or bug fixes. Before testing, do a Pull Request from Main/Master to the Release branch. Also perform Pull Requests from any complete Feature or Bug Fix branches into the Release branch. Fully test the Release branch; this should include unit testing, deployment to a QA environment for integration testing (if possible), followed by user acceptance testing (if required). When it's time to release to production, release the application directly from the Release branch. Once the Release branch is in Production, do a Pull Request from the Release branch up to Main/Master.
Below is a fairly common example showing two features being developed in parallel along with some bug fixes; and two Release branches (one for March and one for May).
There are some downsides to this strategy.
The obvious downside being that Main/Master is never actually deployed or fully tested. In theory, this is generally acceptable, as long as each Release branch is fully tested. One solution to limit issues is to enable automated unit testing and CI/CD against Main/Master, so every Pull Request into Main/Master gets some level of testing.
Branch management also becomes more critical. Abandoned Release, Feature, and Bug Fix branches need to be pruned consistently; meaning a single individual needs to have an all-encompassing view of the application in order to keep the repository organized. Additionally, deployment pipelines can become more complicated as they must regularly release from difference branches. Again, it is critical to keep the deployment pipelines organized when using a Release branch strategy.
Overall, despite the downsides, this solution does work well for large and/or complicated applications.