Git – Branching Strategy
A well-implemented branching strategy is the foundation of an efficient DevOps process. It defines how the delivery team functions, how each feature or bug fix flows from development to production, and how multiple developers can work in parallel without stepping on each other.
Cygnus Dynamics follows a GitFlow-based multi-environment branching model managed through Azure DevOps Repos. This model supports our four-environment pipeline — development, QA, UAT, and production — with clearly defined promotion gates between each stage.
Branch Overview
master ←─── Production (live)
↑
uat ←─── Pre-production / UAT environment
↑
qa ←─── QA / testing environment
↑
develop ←─── Active development integration
↑
feature/* Individual developer work
bugfix/* Non-production bug fixes
hotfix/* Emergency production fixes
release/* Release preparation
Primary Branches
These four branches are permanent — they live for the entire lifetime of the project and are never deleted.
develop
The active development integration branch. This is where all feature and bugfix branches are merged after code review. It represents the latest completed work and is continuously deployed to the development environment.
- All feature branches are created from
develop - All feature branches are merged back into
developvia Pull Request - CI pipeline runs automatically on every push to
develop - Never commit directly to
develop— all changes arrive via PR
qa
The QA testing branch. Once the develop branch is stable and a set of features are ready for testing, the team lead merges develop into qa. The QA environment is deployed from this branch.
- Only receives merges from
develop - QA team validates all functionality in the QA environment
- Bug fixes found during QA are fixed on a
bugfix/*branch, merged todevelop, then re-promoted toqa - No direct commits — promotion only via PR from
develop
uat
The User Acceptance Testing (pre-production) branch. Once qa is stable and QA sign-off is received, the team lead merges qa into uat. The UAT environment mirrors production.
- Only receives merges from
qa - Stakeholder and client acceptance testing happens here
- Represents the final gate before production
- No direct commits — promotion only via PR from
qa
master
The production branch. Contains only production-ready, tested, and approved code. Every merge into master represents a deployment to live production.
- Only receives merges from
uat(for releases) orhotfix/*(for emergency fixes) - All merges into
masterare tagged with the release version - Protected branch — only Tech Leads can approve and merge
- No direct commits under any circumstances
Support Branches
Support branches are short-lived — they are created for a specific purpose and deleted after merging.
feature/* — New Features
Used to develop a new feature. Always branched from develop and merged back into develop via Pull Request.
Naming convention:
| Part | Description | Example |
|---|---|---|
feature/ |
Fixed prefix — identifies branch type | feature/ |
<initials> |
Developer's abbreviated name | rk, as, jm |
<task-name> |
Short kebab-case description of the task | login-page, payment-gateway, user-profile |
Examples:
feature/rk/login-page
feature/as/payment-gateway-integration
feature/jm/order-export-csv
feature/rk/user-profile-settings
Workflow:
# 1. Start from the latest develop
git checkout develop
git pull origin develop
# 2. Create your feature branch
git checkout -b feature/rk/login-page
# 3. Work, commit using Conventional Commits
git add .
git commit -m "feat(auth): add login form with email validation"
# 4. Push to remote
git push origin feature/rk/login-page
# 5. Raise a Pull Request into develop in Azure DevOps
# — see Pull Requests page for PR standards
Always pull latest develop before creating a branch
Starting from a stale develop increases the chance of merge conflicts when you raise your PR. Always git pull origin develop before git checkout -b.
bugfix/* — Non-Production Bug Fixes
Used to fix a bug that was found during development or QA — not a production bug. Always branched from develop and merged back into develop.
Naming convention:
Examples:
bugfix/rk/login-page-validation
bugfix/as/order-total-calculation
bugfix/jm/user-avatar-upload-error
Workflow: Identical to feature/* — branch from develop, fix, PR back to develop.
hotfix/* — Emergency Production Fixes
Used when a critical bug is discovered in production that cannot wait for the next sprint cycle. Hotfixes branch directly from master so the fix does not include unreleased code from develop.
Naming convention:
Examples:
Workflow:
# 1. Branch from master — NOT develop
git checkout master
git pull origin master
git checkout -b hotfix/rk/payment-double-charge
# 2. Fix the issue and commit
git add .
git commit -m "fix(payments): prevent duplicate charge on gateway timeout"
# 3. Raise PR into master — Tech Lead review required
# After merge into master:
# 4. Tag the hotfix release on master
git checkout master
git pull origin master
git tag -a v1.0.1 -m "Hotfix: payment double-charge fix"
git push origin master --tags
# 5. IMPORTANT — also merge the fix into develop
# so it is not lost in the next release
git checkout develop
git merge --no-ff hotfix/rk/payment-double-charge
git push origin develop
# 6. Delete the hotfix branch
git branch -d hotfix/rk/payment-double-charge
git push origin --delete hotfix/rk/payment-double-charge
Hotfixes must merge into BOTH master and develop
If a hotfix is only merged into master, it will be overwritten when the next sprint release is merged from develop. Always merge hotfix branches into both master (for the production fix) and develop (to carry the fix forward).
release/* — Release Preparation
Used to prepare a new production release at the end of a sprint. Created from develop when all sprint features are complete and on qa/uat.
Naming convention:
Examples:
Workflow:
# 1. Create from develop at end of sprint
git checkout develop
git pull origin develop
git checkout -b release/1.0.0
# 2. Final bug fixes only — no new features in a release branch
git commit -m "fix(release): correct version string in package.json"
# 3. PR into master for production deployment
# After approval and merge:
git checkout master
git tag -a v1.0.0 -m "Release 1.0.0"
git push origin master --tags
# 4. Merge release branch back into develop
git checkout develop
git merge --no-ff release/1.0.0
git push origin develop
# 5. Delete release branch
git branch -d release/1.0.0
The Full Flow — Visualised
master ─────────────────────────────●─────────────────────────→ (production)
↑ merge + tag v1.0
uat ───────────────────────●────┘ → (pre-prod)
↑ merge after UAT sign-off
qa ─────────────────●─────┘ → (testing)
↑ merge after dev sign-off
develop ──●──────────────┘──────────────────────────────────────→ (development)
↑↑↑
feature PRs merged here
feature/rk/login ──●──●──●──● ──┘ (merged to develop via PR)
feature/as/orders ─────●──●──●──┘
bugfix/jm/fix-x ───────────●──┘
Creating Branches in Azure DevOps
Cygnus Dynamics manages all repositories in Azure DevOps Repos. Branches can be created from the UI or from the command line.
From Azure DevOps UI
- Navigate to your repository:
https://dev.azure.com/<org>/<project>/_git/<repo> - Go to Repos → Files
- In the branch dropdown, select the source branch (e.g.,
develop) - Click New branch
- Enter the branch name following the naming convention:
feature/rk/login-page - Click Create
From the Command Line
# Ensure you are up-to-date first
git checkout develop
git pull origin develop
# Create and switch to your new branch
git checkout -b feature/rk/login-page
# Push to Azure DevOps remote
git push -u origin feature/rk/login-page
Branch Protection Rules
The following branch protection rules are configured in Azure DevOps for all production repositories:
| Branch | Protections |
|---|---|
master |
Require PR approval; minimum 2 reviewers including Tech Lead; CI must pass; no direct push |
uat |
Require PR approval; minimum 1 reviewer (Tech Lead); CI must pass |
qa |
Require PR approval; minimum 1 reviewer; CI must pass |
develop |
Require PR approval; minimum 1 reviewer; CI must pass |
No engineer — including Tech Leads — may push directly to any primary branch. All changes arrive via Pull Request.
Branch Naming Quick Reference
| Type | Pattern | Example |
|---|---|---|
| Feature | feature/<initials>/<task-name> |
feature/rk/login-page |
| Bug fix (non-prod) | bugfix/<initials>/<task-name> |
bugfix/as/order-total-fix |
| Hotfix (production) | hotfix/<initials>/<description> |
hotfix/rk/payment-double-charge |
| Release | release/<version> |
release/1.0.0 |
Task name rules:
- lowercase only
- hyphens as separators — no underscores or spaces
- descriptive but concise: login-page, payment-gateway, user-profile-settings
- matches or references the ticket/task in Azure Boards where possible
Keeping Your Branch Up To Date
Long-running feature branches accumulate drift from develop. Rebase or merge regularly to stay current and reduce conflict risk:
# Option A — Merge develop into your branch (preserves history)
git checkout feature/rk/my-feature
git fetch origin
git merge origin/develop
# Option B — Rebase onto develop (cleaner linear history)
git checkout feature/rk/my-feature
git fetch origin
git rebase origin/develop
Never rebase a branch that others are working on
Rebasing rewrites commit history. If other developers have checked out your branch, rebasing will cause conflicts for them. Only rebase your own unshared branches.
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
Branching from master for a feature |
Feature is isolated from other team work; will conflict on merge | Always branch from develop |
Committing directly to develop |
Bypasses code review; no peer oversight | Raise a PR — even for trivial changes |
Not merging hotfix to develop |
Fix is lost in next sprint release | Always merge hotfix into both master and develop |
| Leaving stale branches for weeks | Accumulates drift; large merge conflicts | Merge or delete within 2 weeks of creation |
| Using spaces or uppercase in branch names | Breaks CLI tab completion and some CI tools | Use kebab-case only |