3.1 Git Branching Models & Strategy Design

Key Takeaways

  • Trunk-Based Development mandates short-lived topic branches (lifespan < 24 hours) merged into a single shared trunk (main), paired with feature flags to decouple code deployment from feature release.
  • GitFlow utilizes long-lived main and develop branches alongside dedicated feature, release, and hotfix branches, introducing merge debt and integration friction that impedes continuous delivery.
  • GitHub Flow provides a lightweight, main-centric model where feature branches are deployed directly for testing or immediately upon merging into the perpetually deployable main branch.
  • Release branching maintains isolated version-specific code lines for concurrent multi-version support, where bug fixes must be committed forward on main first and cherry-picked back to release branches.
  • On Exam AZ-400, Trunk-Based Development is the primary recommended pattern for cloud-native CI/CD workloads aiming to maximize DORA deployment frequency and minimize change lead time.
Last updated: September 2026

3.1 Git Branching Models & Strategy Design

Quick Summary: In Exam AZ-400, your branching strategy is not merely a team preference—it is the foundational architectural constraint that dictates continuous integration frequency, deployment velocity, and lead time for changes. Trunk-Based Development is Microsoft's recommended default for high-velocity CI/CD paired with feature flags, while GitFlow introduces merge friction unsuitable for modern continuous deployment. Release branching isolates maintenance for multi-version deployments, and GitHub Flow offers lightweight web service delivery.


The Core Philosophy of Source Control in Modern DevOps

Source control management (SCM) in DevOps represents the single source of truth for application code, configuration, and infrastructure definitions. The branching model you implement governs how developers integrate code, how automated validation pipelines trigger, and how changes transition into release artifacts.

From a Lean and DevOps perspective, unintegrated code is inventory. In manufacturing, excess work-in-progress (WIP) inventory increases carrying costs, obscures quality defects, and delays feedback. In software engineering, code sitting isolated on long-lived branches represents unintegrated WIP. The longer a branch diverges from the primary integration branch:

  1. The merge conflict probability scales exponentially, leading to "merge debt" and painful manual reconciliation.
  2. Automated feedback loops are delayed, meaning regression bugs remain undetected until late in the delivery lifecycle.
  3. Batch sizes increase, directly conflicting with the core DevOps principle of small, incremental, low-risk releases.

Designing a Git branching strategy requires balancing isolation (allowing developers to experiment and work without destabilizing others) against integration frequency (merging code early and often to surface incompatibilities immediately).

Branching Isolation vs. Integration Frequency Spectrum:

[Higher Isolation / Lower Integration] ------------------------> [Lower Isolation / Higher Integration]
               GitFlow                        Release Branching          GitHub Flow          Trunk-Based Development
(Long-lived feature & develop branches)     (Isolated stable versions)  (Short PR branches)   (Short-lived <24h branches + Feature Flags)

Deep Dive: Trunk-Based Development (TBD)

Trunk-Based Development is the industry standard branching model for high-performing engineering teams practicing Continuous Integration (CI) and Continuous Delivery (CD). It forms the operational core of the DevOps Research and Assessment (DORA) high-performance benchmarks.

Core Tenets of Trunk-Based Development

  • Single Shared Mainline: All developers commit to a single shared branch, universally referred to as trunk or main. There are no secondary integration branches such as develop.
  • Short-Lived Branches: Developers create short-lived topic branches (often termed "short-lived feature branches") created off the latest commit on main. These branches exist for hours, strictly fewer than 24 hours, and typically comprise 1 to 3 atomic commits.
  • High Integration Cadence: Developers merge their branches back into main at least once per day—and frequently multiple times per day. Every merge is validated by automated CI pipelines that run unit tests, security scans, and build verifications.
  • Direct Commits for Small Teams: Very small, highly mature pairs or teams (2–3 engineers) may commit directly to main using pair programming, though enterprise environments universally enforce lightweight pull requests (PRs) with automated branch policies.
Trunk-Based Development Workflow:

main   o---o---o---o---o---o---o---o---o---o (Trunk: Always Releasable)
            \     /     \     /
feat-A       o---o       |   |  (Branch lifespan < 24 hours)
feat-B                   o---o  (Merged via fast PR + CI gate)

Decoupling Deployment from Release via Feature Flags

A common objection to Trunk-Based Development is: "How can we integrate code into main daily if a business feature takes two weeks to build?"

The answer is Feature Flags (Feature Toggles). Feature flags allow developers to separate deployment (physically placing executable code into production environments) from release (exposing that functionality to end users).

// Example: Consuming Azure App Configuration Feature Manager in C#
public class CheckoutService
{
    private readonly IFeatureManager _featureManager;
    
    public CheckoutService(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    public async Task<OrderResult> ProcessPaymentAsync(OrderDetails order)
    {
        // Dark launching: new code path deployed to production but hidden behind a flag
        if (await _featureManager.IsEnabledAsync("EnableStripeV3PaymentEngine"))
        {
            return await ProcessStripeV3Async(order);
        }
        
        // Fallback to legacy stable engine
        return await ProcessLegacyPaymentAsync(order);
    }
}

By wrapping incomplete features in feature flags:

  • Code can be merged to main and deployed directly to production in an inactive ("dark") state.
  • Developers avoid long-lived branches and merge hell.
  • Operations teams can dynamically toggle features on or off in production via Azure App Configuration without redeploying code.
  • Canary deployments, percentage-based rollouts, and ring-based deployments become trivial.

Deep Dive: GitFlow

Created by Vincent Driessen in 2010, GitFlow was designed for scheduled, packaged software releases with traditional distribution cadences (such as boxed desktop software or milestone-based enterprise systems).

The GitFlow Branch Archetypes

GitFlow defines five strict branch categories with explicit rules governing who can branch from where and where merges must terminate:

  1. main (or master): Stores official production release history. Every commit on main represents a production deployment and is tagged with an immutable release version (e.g., v1.0.0, v1.1.0). Developers never commit directly to main.
  2. develop: The central integration branch for day-to-day development. It aggregates completed features that are waiting for the next scheduled release. develop serves as the parent branch for feature branches.
  3. feature/*: Branched off develop. Developers work on isolated features here. When the feature is complete, it is merged exclusively back into develop. Feature branches never interact directly with main.
  4. release/*: Branched off develop when all features intended for an upcoming release have been integrated. No new substantial features can be added on a release branch; it is reserved strictly for documentation generation, version number bumps, and minor bug fixing. Once stable, the release branch is merged into both main AND develop, and a version tag is applied to main.
  5. hotfix/*: Branched directly off main to address critical, catastrophic defects discovered in production that cannot wait for the next release cycle. Once the fix is applied, the hotfix branch is merged into both main (with a patch tag, e.g., v1.0.1) AND develop (or into the active release/* branch if one is currently open).

The Bidirectional Merge Requirement

A critical structural rule of GitFlow that often confuses teams and causes exam traps is the bidirectional merge-back rule:

Release Branch Closure    (releasemain)(releasedevelop)\text{Release Branch Closure} \implies (\text{release} \to \text{main}) \land (\text{release} \to \text{develop}) Hotfix Branch Closure    (hotfixmain)(hotfixdevelop)\text{Hotfix Branch Closure} \implies (\text{hotfix} \to \text{main}) \land (\text{hotfix} \to \text{develop})

If the hotfix is merged only to main, the defect fix will be missing from develop and will regress the next time develop is released!

Why GitFlow Conflicts with Modern CI/CD

While GitFlow provided structure to teams transitioning from Subversion (SVN) to Git, it creates severe impediments in cloud-native, continuous delivery environments:

  • Merge Debt: Long-lived feature/* branches often diverge from develop for weeks or months. When multiple features finally merge back, teams encounter catastrophic merge conflicts ("merge hell").
  • Delayed Integration: Code integrated into develop is not yet running in production. Defect discovery is postponed to late hardening stages.
  • Pipeline Friction: Maintaining separate CI/CD triggers, artifact builds, and deployment gates for develop, release/*, main, and hotfix/* creates immense pipeline complexity in Azure Pipelines and GitHub Actions.

[!WARNING] AZ-400 Exam Trap: Questions often present scenarios where a development team experiences frequent merge conflicts, slow releases, and difficulty maintaining automated pipelines. If the team is currently using GitFlow and wants to move toward continuous deployment and microservices, the solution is to migrate to Trunk-Based Development, not to add more release branches or complex manual approval gates.


Deep Dive: GitHub Flow

GitHub Flow is a lightweight, simplified alternative to GitFlow designed by GitHub for web applications and microservices deployed continuously to production.

The Six Operational Steps of GitHub Flow

  1. main is Always Releasable: The main branch contains code that is currently running in production or is strictly ready to deploy at any moment.
  2. Descriptive Feature Branches: To implement an enhancement or bug fix, create a branch off main with a descriptive, semantic name (e.g., feature/add-oauth-provider, fix/issue-412-cart-timeout).
  3. Frequent Pushes: Commit locally and push commits regularly to the remote branch on GitHub or Azure Repos, enabling automated CI validation and peer visibility.
  4. Open a Pull Request: Open a PR early in the process. Pull requests are not just approval requests; they are collaborative review forums to discuss implementation, review test runs, and iterate.
  5. Deploy for Verification: Deploy the branch to a staging environment, testing slot, or ephemeral preview environment directly from the PR branch to verify behavior under production-like conditions.
  6. Merge and Deploy to Production: Once peer approvals and automated quality gates pass, merge the PR into main. The merge to main immediately triggers the CD release pipeline to production.

Unlike GitFlow, GitHub Flow completely dispenses with develop, release/*, and hotfix/* branches. All fixes—including urgent production hotfixes—follow the exact same workflow: branch from main, open PR, merge back to main, and deploy.


Deep Dive: Release Branching (Maintenance Branching)

While Trunk-Based Development and GitHub Flow excel for single-version cloud SaaS products, enterprise architectures frequently encounter scenarios where multiple versions of software must be supported simultaneously.

Scenarios Requiring Release Branching

  • On-Premises Software: An organization ships packaged software to clients. Customers on Version 2.4 refuse to upgrade to Version 3.0 immediately, requiring security patches for v2.4 for two years.
  • Mobile Application Distribution: Mobile apps submitted to the Apple App Store or Google Play Store undergo a review period of several days. Development on the next sprint must proceed on main while the submitted version is locked on a release branch.
  • Regulated Compliance Milestones: Medical devices or banking APIs require formal qualification and sign-off on a specific immutable build before deployment.

Architecture of Release Branching

In Release Branching:

  1. Active development proceeds continuously on main.
  2. When a release milestone approaches, a dedicated branch is cut from main named release/v1.2 or release/2026.09.
  3. The release branch undergoes deployment hardening, environment-specific testing, and artifact generation.
  4. Meanwhile, developers continue adding features for the next release on main without destabilizing the release branch.

Defect Resolution: Fix-Forward vs. Cherry-Picking

When a bug is discovered on a release branch, how should it be patched?

Release Branching and Cherry-Picking Topology:

main           o---o---o---[BUG FIX]o---o---o---o (Fix implemented on main first)
                        \          \
release/v2.1             o---o---o--[CHERRY-PICK] (git cherry-pick applied to v2.1)

There are two primary patterns, but one is strongly favored on the AZ-400 exam:

  • The Recommended Pattern (Fix Forward on Main, Cherry-Pick Back): Fix the defect directly on main first. Verify the fix through standard CI pipelines. Then, use git cherry-pick <commit-sha> to apply the exact commit patch to release/v2.1. This ensures the bug is fundamentally fixed for all future releases and prevents regression.
  • The Alternative Pattern (Fix on Release, Merge Back): Fix the defect on release/v2.1, then merge release/v2.1 back into main. This pattern carries high risk: merging a maintenance branch back into main often introduces unintended configuration changes, version regressions, or complex conflicts.
# CLI: Cherry-picking a fix from main to a release branch
git checkout main
# ... developer commits bug fix to main with SHA a1b2c3d ...
git push origin main

# Switch to maintenance release branch
git checkout release/v2.1
git pull origin release/v2.1

# Apply the specific fix commit cleanly
git cherry-pick a1b2c3d
git push origin release/v2.1

Branching Strategy Selection Decision Matrix

Selecting the right branching model depends on organizational variables:

CriteriaTrunk-Based DevelopmentGitFlowGitHub FlowRelease Branching
Primary Mainline(s)Single main (trunk)Dual: main & developSingle mainmain + isolated release/*
Branch LifespanVery Short (< 24 hours)Long (days, weeks, or months)Short (1–3 days)Permanent main + temporary release lines
Deployment FrequencyMultiple times per day (CD)Scheduled / Batch releases (weeks/months)Continuous / DailyPer release schedule per version
Feature Flag RequirementMandatory for uncompleted workOptional (relies on branch isolation)RecommendedOptional
Merge ComplexityMinimal (micro-diffs, daily integration)High (frequent merge conflicts, merge hell)Low to ModerateLow on main, Moderate during backports
Supported VersionsExactly 1 (Current production)Exactly 1 active at a timeExactly 1 (Current production)Multiple concurrent versions
Target ArchitectureMicroservices, Cloud-Native SaaSLegacy monoliths, shrink-wrapped softwareWeb apps, APIs, SaaSMobile apps, on-premises enterprise software
AZ-400 RecommendationPrimary Gold StandardLegacy / Discouraged for CI/CDExcellent for lightweight SaaSEssential for multi-version compliance

Branching Model Topologies

The following diagram contrasts the topological flow of Trunk-Based Development with GitFlow:

graph TD
    subgraph TBD["Trunk-Based Development (Recommended for CI/CD)"]
        T1["main: commit A"] --> T2["main: commit B"]
        T2 --> T3["main: commit C (PR from feat-1 merged)"]
        T3 --> T4["main: commit D (PR from feat-2 merged)"]
        T2 -.-> F1["feat-1 (lifespan < 24h)"]
        F1 -.-> T3
        T3 -.-> F2["feat-2 (lifespan < 24h)"]
        F2 -.-> T4
    end

    subgraph GF["GitFlow (Traditional Scheduled Releases)"]
        M1["main: v1.0.0"] --> M2["main: v1.1.0"]
        D1["develop"] --> D2["develop"]
        D2 --> D3["develop"]
        D1 -.-> GFF1["feature/cart (weeks)"]
        GFF1 -.-> D2
        D2 -.-> REL["release/v1.1.0"]
        REL -.-> M2
        REL -.-> D3
        M1 -.-> HF["hotfix/v1.0.1"]
        HF -.-> M2
        HF -.-> D1
    end

Practical AZ-400 Exam Scenarios & Anti-Patterns

Scenario 1: Transitioning to Continuous Deployment

  • Scenario: A software company deploys an e-commerce platform using GitFlow. Developers work on feature/* branches for 3 weeks before merging to develop. Every release takes 4 days of manual testing on a release/* branch, and merging back to main consistently results in regressions.
  • AZ-400 Solution: Migrate to Trunk-Based Development. Enforce branch policies limiting feature branch lifespans to under 24 hours. Implement Azure App Configuration Feature Manager to wrap incomplete user stories. Configure automated PR validation builds in Azure Pipelines to run comprehensive unit and integration test suites on every pull request.

Scenario 2: Legacy On-Premises API Support

  • Scenario: An enterprise provides an SDK to financial institutions. Forty clients run Version 4.2 in on-premises data centers, while the cloud product has moved to Version 5.0. A zero-day vulnerability is discovered that affects both versions.
  • AZ-400 Solution: Implement Release Branching. Author the patch on main (Version 5.0), validate via pipeline, and commit. Then execute git checkout release/v4.2 and run git cherry-pick <commit-sha> to apply the exact fix to the maintenance branch. Trigger an automated release pipeline from release/v4.2 to publish the patched v4.2.1 package.
Loading diagram...
Trunk-Based Development vs. GitFlow Branch Topologies
Test Your Knowledge

A development team wants to adopt Trunk-Based Development for a microservices application deployed to Azure Kubernetes Service (AKS). However, several complex user stories take up to two weeks to fully code and test. How should the DevOps engineer configure the workflow to allow daily merges to the main branch without exposing unfinished features to end users?

A
B
C
D
Test Your Knowledge

An enterprise maintains a SaaS application in Azure while simultaneously supporting three legacy on-premises releases (v2.1, v2.2, and v2.3) deployed in client data centers. A critical security flaw is discovered that impacts both the current SaaS product and all three legacy versions. What is the recommended Git branching and patch strategy to eliminate regressions in future releases?

A
B
C
D
Test Your Knowledge

What is the primary operational risk and anti-pattern associated with using GitFlow in high-velocity teams striving for continuous deployment?

A
B
C
D