Skip to content
CAMPUX Cloud Bootcamp Phase Three · Class Nineteen
Phase Three — DevOps Core
Reading 38 min · Drills 6 · 2 Labs
Aligned to AZ-400
Class Nineteen

Branching strategies

Every team argues about how branches should flow, and the argument is rarely about Git — it is about how often you dare to ship, which is the number that quietly decides how the whole team works.

● Screen walkthrough Not yet recorded · ~6 min
Reel · 00:00 / 06:00

Branch, merge, and resolve a conflict live — the red text everyone panics at, fixed calmly.

Placeholder — the class below stands alone until the reel lands
§1

The question every team fights about

You now know how to make a branch and how to guard main. The next question is one every team argues about, sometimes bitterly: how should branches be arranged over time? When do you cut one, how long does it live, and how does its work reach production? This is a branching strategy — a team's agreed convention for the shape of its history — and there is no shortage of dogma about it. The trap is treating it as a matter of taste or seniority. It is neither. It is a consequence of one number.1

Branching strategy
A team's shared rules for how branches are created, how long they live, and how their work is integrated and released. Not a Git feature — a social contract the tooling then enforces.

The number is deployment frequency: how often the team actually ships to production. A team that releases once a quarter has different needs from one that ships thirty times a day, and almost every honest disagreement about branching dissolves once you ask that question first. The two strategies this class compares — GitFlow and trunk-based development — are not good and evil; they are answers to different deployment frequencies, and choosing between them by fashion instead of frequency is how teams end up fighting their own process. Get this right and branching becomes invisible, the way it should be. Get it wrong and the strategy itself becomes a daily tax on everyone.

§2

GitFlow: what it solved in 2010

In 2010 a developer named Vincent Driessen published a branching model that became so popular it got a name: GitFlow. To understand why it looks the way it does, remember the world it was born into. Software shipped on a schedule — versioned releases, every few weeks or months, often installed by customers rather than deployed by you. In that world you needed somewhere to stabilise the next release while ongoing work continued, and somewhere to patch the version already in the wild. GitFlow gave each of those a long-lived branch.

main
Holds only released, tagged versions — the history of what actually shipped.
develop
The long-lived integration branch where finished features accumulate between releases.
feature/*
One per feature, branched off develop and merged back when done — often living for weeks.
release/* and hotfix/*
A branch to stabilise the next version, and a branch to patch the current one in production.

For its moment, this was genuinely good engineering: it gave a versioned, ship-it-in-boxes product a clear place for every kind of work. But look at what it costs. Feature branches live long, so they drift far from develop and merge back in painful, conflict-heavy heaves. There are five kinds of branch to keep straight and a ceremony for moving between them. All of that friction is the price of decoupling "written" from "released" — and that price only makes sense if you release rarely. The moment your team wants to ship every day, GitFlow's careful machinery becomes the thing slowing you down.2

§3

Trunk-based: the straight line most cloud teams run

The modern default for teams that deploy often is almost the opposite of GitFlow. In trunk-based development there is one long-lived branch — the trunk, usually main — and everyone integrates into it constantly. You still use branches, but they are short-lived: a branch cut this morning, opened as a PR, reviewed, and merged back the same day. Nothing is allowed to drift for weeks. The trunk is kept releasable at all times, and shipping is a matter of deploying the trunk, not of merging a pile of aged branches together.

Figure 1: two branching strategies side by side. On the left, GitFlow, with several long-lived lanes — main, develop, and feature branches — whose merges tangle together, with a red pen circle around a knot of conflicting merges. On the right, trunk-based development, a single straight trunk with small short-lived branches that pop off and merge back almost immediately. GitFlow — long-lived lanes main dev merge conflicts pile up Trunk-based — one line trunk always releasable
Figure 1 The same work, two shapes. GitFlow's long-lived lanes decouple "written" from "released," but the longer a branch lives the further it drifts, and the merges knot together where the red pen circles. Trunk-based keeps one line and lets branches live only hours, so integration is small and constant instead of large and dreaded. Neither is wrong — but only one stays sane when you ship every day.

Why does short-lived win for cloud teams? Because the pain of merging grows with the age of a branch, and trunk-based simply refuses to let branches get old. Small, frequent integrations mean small, frequent conflicts — the kind resolved in a minute, not a war. It leans hard on the machinery you already have: a protected trunk, required reviews, and automated checks on every PR, so that constant integration does not mean constant breakage. Feature flags do the rest, letting unfinished work sit merged-but-hidden on the trunk rather than marooned on a branch.3 The whole approach is built for the team that deploys many times a day and cannot afford a merge ceremony each time.

One more name belongs in your vocabulary, because interviewers ask for the three-way comparison. GitHub Flow is the middle strategy — the one the GitHub doc linked in the Watch panel describes: branch from main, open a pull request, merge, deploy, and nothing else — no develop branch, no release/* branches, no ceremony beyond the PR. It sits between this class's two poles: lighter than GitFlow by every measure, but more relaxed than strict trunk-based about how long a branch lives and how automatically the trunk deploys. When a team says "we just branch and PR," GitHub Flow is usually what they are describing without knowing its name.

What "protected" actually means

Trunk-based development only stays sane because the trunk is not a branch anyone can push to on a whim — it is protected, and the protection is a set of rules the platform enforces on every attempt to change it. On GitHub these are branch protection rules (Azure DevOps calls the same thing branch policies); the names differ, the ideas are identical, and an interviewer expects you to name them without notes.

Require a pull request
No direct pushes to the trunk. Every change arrives through a PR, so every change has a place to be reviewed and a record of why it went in.
Require approvals
At least one reviewer — often two, or a specific owner — must approve before merge. This is the human gate, and it is why nobody merges their own unreviewed work into what production ships.
Require status checks
The build, the tests, the linter, the security scan must pass on the PR before the merge button lights up. The machine gate — a red check blocks the merge, not just frowns at it.
Require up-to-date branches
The branch must be current with the trunk before merging, so checks run against what will actually land, not against a stale starting point.
CODEOWNERS
A file mapping paths to required reviewers, so a change under /infra automatically pulls in the platform team. Ownership becomes policy, not a favour you remember to ask.

Read the list and notice what it buys: the trunk becomes something that cannot receive unreviewed, unbuilt, untested code, no matter who is in a hurry. That guarantee is the entire foundation trunk-based rests on — "keep the trunk always releasable" is a wish until branch protection makes it a rule the platform will not let you break. It is also the answer to a favourite interview question, "how do you stop someone pushing straight to main?" You do not stop them with a policy on a wiki; you stop them with a protection rule that returns an error. Configure it once, and the discipline is no longer a matter of everyone remembering — which is the only kind of discipline that survives a Friday afternoon and a production incident at once.

§4

Releases and environments

"Ship the trunk" raises an obvious question: ship it where, and how do you gain confidence before it reaches customers? The answer is not more branches — it is more environments. Instead of a develop branch to stabilise on, a modern team promotes the same build through a sequence of running environments, and the trunk stays the single source of truth.

Table 1 — Two ways to reach production
GitFlow-styleTrunk + environments
Where work stabilisesOn a long-lived branch (develop, release/*)In running environments (dev → test → prod)
What differs between stagesDifferent branches of codeThe same build, different config
How a fix reaches prodMerge across branches, in orderMerge to trunk, promote the build forward
Failure modeBranches drift; merges rotA bad build is caught in an early environment

The distinction to hold is promotion, not re-branching. A change merges once to the trunk, produces one artifact, and that same artifact is deployed to dev, then to a test or staging environment, then — behind an approval gate — to production. The code does not change as it moves; only the environment it runs in and the configuration it reads do. Some teams keep a thin release/* branch for a slower cadence or a supported version, and that is a legitimate hybrid — but the everyday flow is trunk to artifact to environments. This is exactly the shape Build III will construct: a pipeline that deploys the trunk to non-prod on merge and waits for a human to approve production. Environments, not branches, are where release confidence is earned.

Figure: promotion, not re-branching. On the left a short trunk with three commits produces, via a build-once arrow, a single artifact box. The same artifact then moves right through a dev environment box and a test environment box, passes an approval gate drawn across the arrow, and lands in prod. A note underneath records that the code does not change as it moves — only the environment and its configuration do. trunk build once one artifact dev config only test config only approval prod customers the code never changes as it moves — only the environment does
Figure — Promotion, not re-branching One merge, one build, one artifact — then the same bits move right through dev and test and wait at a human approval before prod. GitFlow stabilised on branches of code; this stabilises in environments of runtime, and the trunk stays the single source of truth. This is the exact shape Build III constructs.

The same machinery answers the question GitFlow reserved a whole branch type for: the production hotfix. In trunk-based there is no hotfix/*. A fix for a live incident is simply the next change — a short-lived branch off the trunk, a fast PR, a merge — followed by the ordinary promotion path run quickly: the new artifact clears dev and test in minutes and reaches production through the same approval gate, expedited rather than bypassed. The discipline matters more at two in the morning, not less; the fix that skips the pipeline is the fix that ships untested to a system that is already down. GitFlow patched the released version on its own branch and back-merged the patch everywhere; trunk-based fixes the trunk and promotes — one path, run faster.

When a release branch still earns its keep

None of this makes the release/* branch obsolete — it makes it a specialist tool rather than the everyday spine, and the distinction is exactly what a good answer draws. The honest case for a release branch is supporting more than one version in the field at the same time. If Campux's platform is only ever the single thing running in Azure, there is nothing to support but the trunk, and a release branch is pure overhead. But the moment you ship software that customers install and pin — a big client stays on v2 for a year while the trunk races ahead to v3 — you need a living line where v2 can receive security fixes without inheriting v3's new behaviour. That line is a release branch, cut at the release and kept alive as long as the version is supported.

Fixing a bug in that world means writing the fix once on the trunk and then backporting it to each supported release branch, which is what git cherry-pick is for: it copies one specific commit onto another branch without dragging along everything around it. The cost is real and worth stating plainly — every supported version is a branch you must test, build, and patch, so two supported versions is roughly double the release work and three is triple. That arithmetic is the whole reason cloud teams, who run exactly one version of their own service, avoid release branches entirely, while a vendor shipping installed software cannot. Choose the branch when you are genuinely carrying versions; refuse it when you are not — and be able to say which situation you are in, because that sentence is the difference between an engineer and a ritual.

Play

Play it through

Four minutes, two things to do. Checkout is down, and a develop branch and a feature branch are both mid-flight. Cut the hotfix from the one that is actually live, ship it, then bring the fix home. It plays on its own and stops when it needs your hands.

§5

The machinery, and the bill

Everything so far has been about the shape of history. The rest of what a senior engineer is expected to say lives underneath that shape: how you hold "shipped" apart from "shown to a customer," how you give a release a durable name, how you keep a busy trunk from breaking under many hands at once, and what all of it costs the pipeline in minutes. None of these is a branching strategy on its own — they are the parts that make trunk-based actually survive contact with a real team.

Deploy is not release

Start with the sentence that reorganises how you think about shipping: deploying code and releasing a feature are two different events. Deploy means the bits are running in production. Release means a user can see the behaviour. §4 kept them apart with environments; a feature flag keeps them apart within production itself — a runtime switch that lets code sit deployed but dark until you choose to turn it on. This is the mechanism behind the answer you gave in Situation 02: unfinished work merges to the trunk switched off, so "on main" never means "live to customers." The branch strategy stops mattering the moment the flag, not the merge, decides what a user sees.

Feature flag
A named runtime switch, read from configuration rather than compiled into the code, that turns a code path on or off without a redeploy. It moves the release decision out of the pipeline and into an operator's hands.

On Azure the sanctioned home for these switches is App Configuration's Feature Manager — a central store where a flag is data, not code, so flipping it takes effect without rebuilding or redeploying anything. Its value is not the on/off; it is the targeting: turn a feature on for internal users first, then for one region, then for five percent of stores, then for all. That progressive turn-up is exactly what deployment strategies like canary and blue-green rollouts are built on, which a later class treats in full4 — and it is only possible because the code was already deployed, waiting behind the flag. The flag, not a branch, is where release risk is now managed.

Semantic versioning: giving a release a name

"Deploy the trunk" is a fine instruction until an incident makes someone ask which trunk — which exact state of the code is running right now. A branch cannot answer that; branches move. A tag can, because a tag is a permanent label pinned to one commit, and the durable name of a release is a tag on the trunk commit that shipped it. The convention almost everyone uses to choose that name is semantic versioning: three numbers, MAJOR.MINOR.PATCH, each of which tells a reader what changed without reading the diff.

Semantic versioning
A convention for release numbers — MAJOR.MINOR.PATCH — where each position carries a promise about compatibility, so a version string alone tells you whether an upgrade is safe.
MAJOR
Bumped for a change that breaks compatibility — callers must alter their code. 1.9.0 to 2.0.0 is a warning, not a routine update.
MINOR
Bumped for a backward-compatible feature — new behaviour that does not break the old. 2.0.0 to 2.1.0.
PATCH
Bumped for a backward-compatible fix — the hotfix from §4 lands here. 2.1.0 to 2.1.1.

This is what turns §4's abstract v2 and v3 into real objects. The release branch that supports a pinned customer is cut at a tag — v2.4.0 — and every security fix backported onto it is another PATCH bump, v2.4.1, while the trunk races toward v3.0.0. The version string is doing the work of a whole conversation: a customer reading 2.4.1 knows it is their line, patched, with nothing new to fear. For a cloud team running one version of its own service the tag is mostly a receipt — what shipped, when, so an incident can name it — but even a receipt is worth having at three in the morning.

The merge queue

Branch protection from §3 checks each pull request against the trunk on its own. That is enough until the trunk gets busy, and then a subtle failure appears: two PRs are each green against main separately, yet break the moment both land, because neither was ever tested against the other. One renames a function; the other adds a caller of the old name; both pass; the merged trunk does not build. At a few merges a day you shrug and re-run. At forty an hour, the trunk is broken more often than not, and "always releasable" quietly becomes a lie.

A merge queue is the fix, and it is worth being able to describe. Instead of merging approved PRs immediately, the platform lines them up and tests each one against the trunk plus the PRs already ahead of it in the queue — the exact state it will create. Green, and it merges in order; red, and it is evicted from the queue without ever touching the trunk, so the offending pair is caught before it lands rather than after. GitHub offers this as a built-in merge queue; Azure DevOps has no direct equivalent, so teams there approximate it with stricter build-validation policies and a habit of merging one PR at a time on a busy trunk. Where a real merge queue exists, it is the piece that lets many people integrate into one trunk all day and keep the "protected, always releasable" promise literally true — the machine version of the discipline §3 described.

What the strategy costs your pipeline

A branching strategy is also a bill, paid in pipeline minutes, and pretending otherwise is how a team is surprised by its own invoice. Trunk-based produces many small pull requests, so the pipeline runs often — but each run is small and fast, and feedback arrives in minutes. Long-lived branches invert it: fewer runs, but each is a monster, and a break blocks everyone downstream. A merge queue buys a trustworthy trunk by spending more compute, because every candidate is retested against the queue ahead of it. There is no free option here; there is only knowing which one you are buying.

Table 2 — What each choice costs the pipeline
ChoicePipeline minutesTrunk stabilityFeedback speed
Long-lived branchesFewer runs, each largeFragile — a stale merge can break it for everyoneSlow — problems surface at merge, weeks late
Short-lived + trunkMany runs, each smallGood — small changes, fast to revertFast — minutes per PR
Add a merge queueHighest — every candidate retested in orderHighest — the trunk is tested as it will landSlightly delayed by the queue, but reliable

The tuning is real engineering, and it connects straight to money: the runner minutes you spend here are the FinOps line a later class prices, and the way you shave them — path filters so a docs change does not rebuild the world, caching, right-sized runners — is a skill in itself. But do the cheap thing first. A team drowning in CI cost usually has branches that are too long and PRs that are too big, not a runner that is too small; the batch size you chose in §1 is upstream of the bill you pay here.

§6

Choose by frequency, not ideology

Now the decision, made honestly. You do not pick a branching strategy because it is "enterprise" or "what Google does" — you pick it by asking how often your team ships, then working backward.

Choose by frequency, not by fashion.

Ship many times a day
Trunk-based with short-lived branches and environment promotion. Long-lived branches would knot; you cannot afford a merge ceremony per release.
Ship on a slow, versioned cadence
A GitFlow-style model, or trunk plus a release/* branch, earns its overhead — you genuinely need to stabilise a version and patch old ones.
Somewhere in between
Most teams: trunk-based as the spine, with a light release branch only where a supported version demands it. Start simple; add branches only when a real need appears.

The failure mode to recognise in yourself and others is cargo-culting — adopting GitFlow's five-branch dance for a team that deploys daily, or forcing bleeding-edge trunk-based onto a team shipping firmware once a quarter. Both are the same mistake: choosing by identity instead of by deployment frequency. For most cloud infrastructure work — which is where you are headed — the honest answer in an interview is "trunk-based development with short-lived branches, protected trunk, and promotion through environments," because that is what deploying infrastructure many times a day actually requires. Know GitFlow well enough to explain what it solved and why it fell out of favour; that pairing — knowing both, and knowing why you chose one — is what separates an engineer from someone reciting a blog post.

Case File · Campux Retail

Picking the flow the platform will live by

campux-platform goes trunk-based

Campux's new lead, fresh from a big enterprise, opens with "we should run GitFlow — it is what serious companies use." You ask the question this class is built on: how often will we ship? The answer, for infrastructure that changes almost daily, settles it. GitFlow's develop and long release branches would have the team merging aged, conflicting changes into campux-platform constantly — the exact tangle Figure 1 circles in red. Campux commits to trunk-based: one protected main, branches that live hours not weeks, and every change reviewed on the way in.

Release confidence moves off branches and onto environments. The trunk builds one artifact; that artifact deploys to a non-prod environment on merge, and reaches production only behind a human approval. This is the shape Build III will implement for real — and it is a decision made on numbers, not on whose last employer did what. When the lead asks how they will support an older version if a big client ever pins one, you keep the door open: a thin release/* branch, added only if and when that need actually arrives.

Watch · Microsoft Learn

The official module, and a CAMPUX overview

Read or work the module first; watch the overview to see it move
Microsoft Learn · Module

Design and implement branch strategies and workflows
learn.microsoft.com/training/modules/manage-git-branches-workflows/

GitHub Docs · Understanding the GitHub flow
docs.github.com/get-started/using-github/github-flow

CAMPUX overview video

A short walkthrough of GitFlow's tangle versus a trunk-based straight line, and how environments replace release branches, will live here. Video to be added.

Lab 1 · Trunk-based flow

Short-lived branch, in and out the same session

~8 minutes · the campux-platform repo · one protected trunk

You cut the hotfix from main above. Now do it for real. Feel the trunk-based loop at its natural speed: branch, change, PR, merge, delete — all in one sitting. The point is that the branch never gets old enough to drift.

  1. Start from an up-to-date trunk, then cut a short-lived branch:

    git switch main
    git pull
    git switch -c add-contributing
    What just happened: you branched from the latest main. Because you pulled first, the branch starts life with zero drift — the ideal it will try to keep by not living long.
  2. Make one small change and push the branch:

    printf "\n## Contributing\nBranch, PR, review, merge, delete.\n" >> README.md
    git commit -am "Document the contribution flow"
    git push -u origin add-contributing
    On screen: GitHub prints a link to open a PR. One focused change on a fresh branch is exactly what a reviewer can read in minutes.
  3. Open the PR, let the checks and review pass, and merge it — then delete the branch when GitHub offers.

    What to notice: the branch existed for minutes and is now gone. Its work lives on the trunk; the PR keeps the history. Nothing is left to rot.
  4. Bring your trunk up to date, then remove the branch on your own machine too — GitHub's delete button only removed the remote copy:

    git switch main
    git pull
    git branch -d add-contributing
    git branch
    What to notice: -d only works because the branch's work is already merged into main — Git checks that before it lets you delete. git branch now lists only main. The lesson: that is the whole rhythm — start fresh, change small, integrate fast, delete on both ends. Repeat it many times a day and merges never become events.
Lab 2 · The cost of drift

Make a long-lived branch bite you

~10 minutes · same repo · deliberately provoke a conflict

Now feel why trunk-based forbids old branches. You will let two branches edit the same lines while the trunk moves on, then watch the second merge collide — the pain that grows with a branch's age.

  1. From an updated trunk, create two branches that will touch the same line:

    git switch main && git pull
    git switch -c edit-title-a
    sed -i '1s/.*/# Campux Platform — A/' README.md
    git commit -am "Title edit A"
    What just happened: branch A rewrote line one. Keep it unmerged for a moment — it is about to become the "old" branch that drifted.
  2. Make a competing change reach the trunk first, via its own branch and merge:

    git switch main
    git switch -c edit-title-b
    sed -i '1s/.*/# Campux Platform — B/' README.md
    git commit -am "Title edit B"
    git switch main && git merge edit-title-b
    On screen: the trunk now says "— B" on line one. Branch A still says "— A" and was cut before this landed. The two have diverged on the same line.
  3. Try to bring branch A up to date — and hit the conflict:

    git switch edit-title-a
    git merge main
    On screen: CONFLICT in README.md. Git cannot know whether line one should read A or B, so it stops and hands you both, wrapped in <<<<<<< markers.
  4. Resolve it by editing the file to the line you actually want, then finish the merge:

    sed -i '1s/.*/# Campux Platform/' README.md   # pick the real answer
    git add README.md
    git commit --no-edit
    The lesson: this conflict took seconds because only one line diverged. Now imagine a branch that drifted for three weeks across forty files — the same mechanism, multiplied into an afternoon. That multiplication is exactly what short-lived branches exist to prevent. Delete these throwaway branches when done.
Note · sed -i edits in place on Linux and Git Bash for Windows; on macOS use sed -i ''. Any text editor works just as well — the conflict is the point, not the tool.
Think in systems

Zoom out: a branching model is a promise about how often you integrate pain

You can run trunk-based or a release-branch flow. Now reason about what the model does to the whole team, because a branch is deferred integration, and deferred pain compounds.

Feedback loops

Long-lived branches defer merge pain, so they diverge, so the eventual merge is a weekend of conflicts nobody wants to own — which encourages even longer branches. What shrinks the batch back down?

Dependencies & coupling

main is the shared truth everyone depends on; a broken main blocks the whole team, so the model exists first to keep it releasable.

The constraint

Integration frequency is the real lever; the strategy is just how you make small, frequent, reviewed merges the path of least resistance.

Second-order effects

A model tuned for a library’s stability — release branches, careful merges — suffocates a web app that wants to ship daily, and the reverse is equally true.

What breaks when it scales

A flow one team coordinates verbally needs written protection and automation before ten teams share the same main without treading on each other.

The engineer who ships is asked "did it branch clean?" The engineer who gets promoted is asked "and how long until it rejoins the truth?" — and kept the batch small.

On the job

How the team avoids a Friday

You · Cloud Engineer · two features are colliding

Two people are building on top of each other and stepping on toes. You untangle it with a branching strategy that fits the team — short-lived branches off main, merged small and often — so integration happens continuously instead of in one dreaded big-bang merge the night before release. The strategy is not dogma; it is how the team avoids a Friday.

Class Nineteen

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored; this is between you and the page.

Drill 01Recall · strategy matching
A team deploys infrastructure changes many times a day. Which branching strategy fits, and why?
Marked

A. High deployment frequency is the fact that decides it: long-lived branches drift further the longer they live, so a team shipping daily under GitFlow spends its life reconciling aged branches. B chooses by prestige, not frequency — the exact cargo-cult this class warns against. C is GitFlow's failure mode taken to its extreme. D throws away review and protection entirely. Trunk-based keeps branches too young to drift, which is what shipping many times a day actually requires.

Drill 02Recall · environments
In a trunk-based team, how does a change gain confidence before it reaches customers?
Marked

B. Trunk-based moves release confidence off branches and onto environments: the trunk produces one artifact, and that same artifact is promoted forward, changing only its configuration, until a human approves production. A and C are the branch-based habits it replaces; D is the dangerous version — building a different artifact per environment means you never actually tested what you shipped. Promotion, not re-branching, is the idea to hold — and it is the exact shape Build III implements.

Drill 03Select three
Which three are true of trunk-based development?
Marked

Short-lived branches, feature flags for hidden work, and small frequent conflicts. The two false options are the common misreadings: trunk-based is not "commit to main with no review" — it leans harder on protection and checks than any other model, because constant integration would be constant breakage without them. And it does not remove the protected trunk; the protected trunk is precisely what makes it safe to integrate all day. Short branches plus strong guardrails, not a free-for-all.

Drill 04Spot the error
A developer describes their plan for a big feature. One line is the decision that will hurt most. Which?
FEATURE PLAN — as proposed

1.  Cut a feature branch off main today
2.  Build the whole feature over the next 6 weeks on it
3.  Keep it off main until it is 100% finished and perfect
4.  Rebase on main at the very end, then open one big PR
5.  Merge the ~40-file branch in a single review
Marked

Line three. The six-week isolation is the decision every other problem flows from. While the branch sits off main, the trunk moves under it every day; by the end it has drifted so far that the "rebase at the very end" in line four is a minefield and the "single review" in line five is a rubber stamp on forty files nobody can hold in their head.

The fix is not a better merge — it is to never let the branch get old. Slice the feature into small pieces that each merge within a day, hidden behind a feature flag until the whole thing is ready. The work still takes six weeks; it just integrates continuously instead of colliding all at once. Branch age is the enemy, and line three is where the team chose to make it their enemy.

Situation 01Write before you reveal
A new team lead announces the team will adopt GitFlow "because that's what serious enterprises do." Your team deploys infrastructure changes several times a day. You think it is the wrong fit. Make your case — then say what you do once the decision is made.
A strong answer argues on the number, not on taste — and knows when the arguing ends.
Reasoning

Argue on frequency, not identity. Do not say "GitFlow is old" or "trunk-based is better" — those are taste, and taste loses to a lead. Say the number: we deploy several times a day, and GitFlow's long-lived develop and release branches assume a slow, versioned cadence we do not have. Name the concrete cost — daily merges of drifting branches, the exact tangle we are trying to avoid — and offer the alternative in the same breath: trunk-based with a protected trunk and environment promotion, which gives the same safety GitFlow was reaching for, at our speed.

Bring evidence, not just opinion. Point at how the team actually ships today, and if you can, at what GitFlow would have cost on a recent change. The case is strongest when it is about this team's deployment frequency, not a blog post either of you read.

Then commit to the decision, whichever way it lands. If the lead still chooses GitFlow, you implement GitFlow well — disagreeing and committing is a senior trait, not a betrayal of your view. You made the argument on the merits; now the team needs one strategy executed cleanly, not two half-followed. Revisit it later with data if the pain you predicted shows up. Being right is worth less than being someone the team can decide with.

Situation 02Write before you reveal
A stakeholder hears you are moving to trunk-based development and objects: "So half-finished code will be sitting on main — won't that ship broken features to our customers?" How do you answer?
The fear is real; the premise that "on main" equals "in front of customers" is the thing to separate.
Reasoning

Concede the fear before you dissolve it. The worry is legitimate — unfinished work reaching customers would be bad. The move is to separate two things the objection has fused: being merged to main and being visible to a customer. Trunk-based keeps them apart deliberately, so "on main" never means "live to users."

Name the two mechanisms. First, feature flags: unfinished work merges to the trunk switched off, present in the code but dark to users until we choose to turn it on. Second, environments: the trunk deploys to dev and test long before production, and production sits behind an approval gate, so nothing reaches customers unreviewed. Merged, tested, and released are three different events.

Turn it back into the benefit. This is actually safer than the alternative: a giant feature branch merged after six weeks lands as one big, poorly understood change, while small flagged increments are each reviewed and integrated continuously. Customers see a feature the day we flip the flag — not a moment sooner — and by then it has been on the trunk, tested, the whole time. The stakeholder wanted safety; trunk-based with flags is how you give it to them.

Examination record · first attempt
0/4
Class Nineteen · Complete
Retain this much

Five things worth carrying out of this class

  1. A branching strategy is a consequence of one number — how often you ship — not a matter of taste or seniority.
  2. GitFlow's long-lived lanes (main, develop, feature, release, hotfix) suit a slow, versioned cadence; the price is drift and painful merges.
  3. Trunk-based keeps one protected trunk and short-lived branches, so integration is small and constant instead of large and dreaded — the modern default for cloud teams.
  4. Release confidence lives in environments, not branches: promote one build through dev → test → prod. Feature flags keep unfinished work merged but hidden.
  5. Choose by deployment frequency, not fashion. Know both strategies and why you picked one — that pairing is the interview answer.
Notes
  1. "Deployment frequency" is not a slogan — it is one of the four DORA metrics, the research-backed measures of software delivery performance (alongside lead time for changes, change failure rate, and time to restore service). The finding that elite teams both deploy far more often and fail less is what retired the old assumption that speed and safety trade off. Trunk-based development is strongly associated with the high-performing end of that data. Treat the exact rankings with a little suspicion — they are survey-based — but the direction is well replicated.
  2. GitFlow's own author, Vincent Driessen, later added a note to his 2010 post urging readers not to treat it as a default — for teams practising continuous delivery on web apps, he now points them toward simpler, trunk-based flows. This is a healthy thing to cite in an interview: the model is not "wrong", it is a good answer to a question fewer teams are asking. Knowing that history signals you understand the why, not just the diagram.
  3. "Trunk-based development" is sometimes used loosely to mean "commit straight to main", which is a caricature that gives it a bad name. The disciplined version — short-lived branches, a protected trunk, PR review, and automated checks on every change — is the one the research and this class mean. If someone dismisses trunk-based as reckless, they are usually arguing against the caricature; the real practice is more guarded than long-branch models, not less.
  4. Semantic versioning is a convention, not something Git or Azure enforces — nothing stops a team tagging a breaking change as a PATCH bump, and plenty do by accident. Its value is a shared promise, and a promise only holds if everyone keeps it; treat a project's version numbers as a claim to verify, not a guarantee, until you have watched the team honour them once. The canary and blue-green rollout mechanics gestured at here get their own full treatment in the later deployment-strategies material — this class only needs you to see that the flag is what makes them possible.