Skip to content

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 develop via 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 to develop, then re-promoted to qa
  • 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) or hotfix/* (for emergency fixes)
  • All merges into master are 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:

feature/<initials>/<task-name>
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:

bugfix/<initials>/<task-name>

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:

hotfix/<initials>/<issue-description>

Examples:

hotfix/rk/payment-double-charge
hotfix/as/login-500-error

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:

release/<version>

Examples:

release/1.0.0
release/2.3.0
release/2026-Q1

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

  1. Navigate to your repository: https://dev.azure.com/<org>/<project>/_git/<repo>
  2. Go to Repos → Files
  3. In the branch dropdown, select the source branch (e.g., develop)
  4. Click New branch
  5. Enter the branch name following the naming convention: feature/rk/login-page
  6. 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