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.
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:
- The merge conflict probability scales exponentially, leading to "merge debt" and painful manual reconciliation.
- Automated feedback loops are delayed, meaning regression bugs remain undetected until late in the delivery lifecycle.
- 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
trunkormain. There are no secondary integration branches such asdevelop. - 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
mainat 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
mainusing 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
mainand 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:
main(ormaster): Stores official production release history. Every commit onmainrepresents a production deployment and is tagged with an immutable release version (e.g.,v1.0.0,v1.1.0). Developers never commit directly tomain.develop: The central integration branch for day-to-day development. It aggregates completed features that are waiting for the next scheduled release.developserves as the parent branch for feature branches.feature/*: Branched offdevelop. Developers work on isolated features here. When the feature is complete, it is merged exclusively back intodevelop. Feature branches never interact directly withmain.release/*: Branched offdevelopwhen 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 bothmainANDdevelop, and a version tag is applied tomain.hotfix/*: Branched directly offmainto 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 bothmain(with a patch tag, e.g.,v1.0.1) ANDdevelop(or into the activerelease/*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:
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 fromdevelopfor weeks or months. When multiple features finally merge back, teams encounter catastrophic merge conflicts ("merge hell"). - Delayed Integration: Code integrated into
developis 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, andhotfix/*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
mainis Always Releasable: Themainbranch contains code that is currently running in production or is strictly ready to deploy at any moment.- Descriptive Feature Branches: To implement an enhancement or bug fix, create a branch off
mainwith a descriptive, semantic name (e.g.,feature/add-oauth-provider,fix/issue-412-cart-timeout). - Frequent Pushes: Commit locally and push commits regularly to the remote branch on GitHub or Azure Repos, enabling automated CI validation and peer visibility.
- 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.
- 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.
- Merge and Deploy to Production: Once peer approvals and automated quality gates pass, merge the PR into
main. The merge tomainimmediately 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
mainwhile 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:
- Active development proceeds continuously on
main. - When a release milestone approaches, a dedicated branch is cut from
mainnamedrelease/v1.2orrelease/2026.09. - The release branch undergoes deployment hardening, environment-specific testing, and artifact generation.
- Meanwhile, developers continue adding features for the next release on
mainwithout 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
mainfirst. Verify the fix through standard CI pipelines. Then, usegit cherry-pick <commit-sha>to apply the exact commit patch torelease/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 mergerelease/v2.1back intomain. This pattern carries high risk: merging a maintenance branch back intomainoften 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:
| Criteria | Trunk-Based Development | GitFlow | GitHub Flow | Release Branching |
|---|---|---|---|---|
| Primary Mainline(s) | Single main (trunk) | Dual: main & develop | Single main | main + isolated release/* |
| Branch Lifespan | Very Short (< 24 hours) | Long (days, weeks, or months) | Short (1–3 days) | Permanent main + temporary release lines |
| Deployment Frequency | Multiple times per day (CD) | Scheduled / Batch releases (weeks/months) | Continuous / Daily | Per release schedule per version |
| Feature Flag Requirement | Mandatory for uncompleted work | Optional (relies on branch isolation) | Recommended | Optional |
| Merge Complexity | Minimal (micro-diffs, daily integration) | High (frequent merge conflicts, merge hell) | Low to Moderate | Low on main, Moderate during backports |
| Supported Versions | Exactly 1 (Current production) | Exactly 1 active at a time | Exactly 1 (Current production) | Multiple concurrent versions |
| Target Architecture | Microservices, Cloud-Native SaaS | Legacy monoliths, shrink-wrapped software | Web apps, APIs, SaaS | Mobile apps, on-premises enterprise software |
| AZ-400 Recommendation | Primary Gold Standard | Legacy / Discouraged for CI/CD | Excellent for lightweight SaaS | Essential 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 todevelop. Every release takes 4 days of manual testing on arelease/*branch, and merging back tomainconsistently 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 executegit checkout release/v4.2and rungit cherry-pick <commit-sha>to apply the exact fix to the maintenance branch. Trigger an automated release pipeline fromrelease/v4.2to publish the patched v4.2.1 package.
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?
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?
What is the primary operational risk and anti-pattern associated with using GitFlow in high-velocity teams striving for continuous deployment?