Release Engineering Best Practices: Branching Models, CI/CD Guidelines, and Deployment Strategies
This article provides a comprehensive overview of release engineering, covering branch models, naming conventions, merge processes, Git commit standards, CI/CD stage design, environment isolation, artifact management, product delivery steps, deployment strategies, and rollback procedures to ensure reliable software releases.
What is Release Engineering?
Release engineering is an emerging and fast‑growing discipline in software engineering that defines standards for application development and enforces strict processes to ensure reliability at product release. Release engineers are proficient in source‑code management, configuration management, development workflows, and customer support, adapting flexible processes to product needs.
Development Guidelines for Release Engineering
Branch Model
The development guidelines require the use of the git-flow branching model.
Main Branch
The main branch represents production‑ready code, contains the most stable version, and all commits must be tagged with a version number. Direct commits are prohibited; merges require QA approval.
Develop Branch
The develop branch integrates feature branches. Developers and maintainers may merge feature branches into develop, providing brief descriptions of the added functionality.
Feature Branch
Feature branches are children of develop, allowing parallel development of multiple features. Once a feature is designed and tested, the branch is merged back into develop.
Each new feature's code resides in its own feature branch, which can be pushed to the central repository for backup and collaboration.
Feature branches exist only in the developer's repository, not in the origin.
Feature branches never merge directly into main; they merge back into develop after completion.
UAT Branch
The User Acceptance Testing (UAT) branch is a pre‑production branch. After code is developed and tested in develop, it is merged into UAT.
The UAT branch is locked so developers cannot push directly; only maintainers may accept merge/pull requests.
After all tests pass, a release branch is created from UAT. Bug fixes are merged first into develop, not directly into UAT.
Release Branch
A release branch is derived from UAT to start a new release cycle. No new features are added; only documentation, bug fixes, and release‑related tasks occur. Version tags are created here, and after release the branch merges back into main and develop.
Hotfix/Bugfix Branch
Hotfix branches are created from main to quickly patch production issues. After fixing, the hotfix merges into both main and develop, then into the ongoing release branch, and the main branch receives a new version tag.
Branch Naming Conventions
Feature Branch
Feature branch names may use slashes or hyphens as separators and must match the regex /[a-z0-9-]+/ . Examples include feature/* , feature/gitlab-integration , feature/ticket_id , feature-* , feature-slack-integration .
Release Branch
Names follow the pattern release/* , e.g., release-1.0.0 .
Hotfix Branch
Names follow hotfix/* , e.g., hotfix/broken-link .
Merge Process
Developers should follow a proper merge workflow: confirm the target branch, fetch the latest remote commits, and apply the merge. The typical flow is feature/branch_name → develop → UAT → Release → Master .
Git Commit Guidelines
Commit messages should be concise (≤50 characters, ≤72 characters for the body), descriptive, and start with a capitalized subject that does not end with a period. Include issue numbers when relevant. Examples of good messages: "Add Dockerfile" , "Fix github integration error." , "Add Hindi & English translation." .
CI/CD Guidelines for Release Engineering
CI/CD Stages
Each branch defined in the development guidelines must have a strict CI/CD pipeline composed of the stages listed below.
Feature/Hotfix Branch
Unit Testing
Integration Testing
Build
Push
Deploy code (if required)
Develop Branch
Code Quality Check
Unit Testing
Integration Testing
Functional Testing
Build
Push
Deploy to Dev
UAT Branch
SAST
DAST
Browser Performance Testing
Load Testing
Fuzz Testing
Build
Push
Deploy to UAT
Release branches contain only release‑ready code and focus on documentation, final polishing, and minor bug fixes. They may also run a CI/CD pipeline for final verification before merging into main, which then serves only as a mirror of production.
Main (master) branch pipeline includes Build, Push, and Deploy to Prod.
Stage Definitions
Code Quality Check: Automated analysis of source code to ensure simplicity, readability, and contribution friendliness.
Unit Testing: Tests individual units or components at the source‑code level to verify correct behavior.
Integration Testing: Tests combined units to uncover faults in their interactions.
Functional Testing: Black‑box testing that validates the system against functional requirements.
SAST: Static Application Security Testing scans source code and binaries for vulnerabilities before deployment.
DAST: Dynamic Application Security Testing evaluates a running web application for known runtime vulnerabilities.
Browser Performance Testing: Automated testing of web performance, generating artifact reports.
Load Testing: Measures system response under load to inform performance decisions.
Fuzz Testing: Supplies unexpected or random inputs to uncover stability issues and hidden bugs.
Build: Packages source code and dependencies into a Docker image.
Push: Pushes the built Docker image to a private Harbor registry with appropriate tags.
Deploy: Deploys the artifact to the environment associated with the branch (dev, UAT, or prod).
Best Practices for CI/CD Stage Design
All non‑release branches must include Build and Push stages.
Deploy stages are added only when testing requires them; develop deploys to a dedicated dev environment, UAT deploys to a UAT environment, and production deploys from the main branch.
Release branches should not have any pipeline stages; they focus on documentation and final polishing.
Feature/Hotfix pipelines run only unit and integration tests.
Develop pipelines run unit, integration, and functional tests.
UAT pipelines run all security and performance tests (SAST, DAST, browser performance, load, fuzz).
After UAT testing, the main branch pipeline can skip tests and deploy directly.
Environment Definition
Separate isolated environments are required for DEV, UAT, and PROD. Ideally each environment runs on its own Kubernetes cluster; alternatively, a single cluster with distinct namespaces and network policies can be used.
Based on Environment Naming Conventions
Hostnames should follow the pattern: dev.example.com for DEV, uat.example.com for UAT, and example.com for PROD.
Artifact Management
All deliverables—source code, meeting notes, workflow diagrams, data models, risk assessments, use cases, prototypes, and compiled applications—are considered artifacts. They must be versioned and stored in an artifact repository such as Artifactory. Docker images should be tagged with project, repository, branch, and pipeline identifiers (e.g., life-data/stt-server:develop123456 ).
How to Deliver Your Product to End Users?
Product Delivery to End Users
Developers create a Changelog file for each microservice.
The production code must include a README.
QA signs off; without QA approval, code cannot be merged to production.
Product team prepares user and reference documentation.
Sales and marketing obtain a basic understanding of the product before client discussions.
Support team receives training to handle user issues.
Release engineers compile a release checklist covering all necessary items.
After checklist completion, developers create a release branch for version control and tagging, following semantic versioning.
The release branch is merged into the production branch.
How to Choose the Right Deployment Strategy?
Recreate: Terminate all old pods, then start new ones (downtime).
Ramped (Rolling Update): Gradually replace old pods with new ones.
Blue/Green: Deploy new version alongside old, switch traffic after validation.
Canary: Release new version to a subset of users before full rollout.
A/B Testing: Direct a portion of traffic to the new version under specific conditions.
Shadow: Run new version in parallel, mirroring traffic without affecting responses.
Recreate
All existing pods are terminated at once and replaced by new pods, causing downtime. Use when the application cannot tolerate multiple versions or when you need to stop processing old data before starting new workloads.
Rolling Update
Kubernetes default strategy; new pods replace old pods gradually without downtime. The update can be aborted if issues arise. Configuration includes max surge and max unavailable settings.
Blue‑Green
Both old and new versions are deployed simultaneously; QA tests the new version, then traffic is switched. Benefits include zero‑downtime rollbacks and quick disaster recovery, but it incurs higher cost due to duplicate environments.
Canary
A portion of user traffic is routed to the new version to observe behavior before full rollout. Useful for early detection of issues and gathering feedback.
A/B Testing
Routes a subset of users to the new version to evaluate business impact. Provides full control over traffic allocation but requires a costly setup.
Shadow
New version receives a copy of production traffic for testing without affecting real users. Allows performance testing with real load but adds complexity and cost.
What Is a Rollback? Its Role in Release Management
A rollback restores an object to a previous stable state when a deployment is unstable or produces unexpected results.
Identify the cause of the failure via pod logs and status (e.g., CrashLoopBackOff, ImagePullBackOff).
If the issue cannot be fixed, initiate a rollback.
Inspect the rollout history with kubectl rollout history deployment.v1.apps/<deployment-name> to find a stable revision.
Undo to the chosen revision using kubectl rollout undo deployment.v1.apps/<deployment-name> --to-revision=<revision-number> .
Describe the deployment to verify the configuration with kubectl describe deployment <deployment-name> .
By default, Kubernetes retains the last 10 ReplicaSets; this limit can be adjusted via spec.revisionHistoryLimit in the deployment manifest.
Conclusion
Release engineering is a rapidly evolving field that provides a systematic approach from development to reliable product delivery. Organizations must establish robust release engineering processes to ship high‑quality products quickly and safely.
DevOps Cloud Academy
Exploring industry DevOps practices and technical expertise.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.