Gitflow was designed in 2010 for teams doing scheduled releases with long-lived support branches. Most teams today deploy continuously. Running Gitflow on a continuous deployment team means paying for a coordination overhead that no longer matches how the software leaves the building.

This is the workflow that replaces it: trunk-based development with feature flags. Fewer branches, fewer merge conflicts, faster time from commit to production.

Prerequisites

  • A CI pipeline that runs tests on every push

  • Ability to deploy from main directly (or close to it)

  • A feature flag tool — LaunchDarkly, Unleash (open source, self-hostable), or a simple in-house flag table

The core structure

One long-lived branch: main. Everything deploys from it.

main ──●──●──●──●──●──●──●──●──▶
        \    /    \    /
      feature/x  feature/y

Short-lived feature branches fork from main and merge back within a day or two. No develop branch. No release branch. No long-lived hotfix branch.

Step 1: Branch for a feature

git checkout main
git pull origin main
git checkout -b feature/checkout-retry-logic

Naming convention: feature/, fix/, or chore/ prefix, then a short description. This keeps branch lists scannable and makes intent visible without opening the diff.

Step 2: Keep the branch short-lived

Target: merged within 1–2 days. If a feature is going to take longer, that's a signal to split it, not a reason to extend the branch.

Commit and push regularly:

git add .
git commit -m "Add retry logic for failed checkout requests"
git push origin feature/checkout-retry-logic

Rebase against main daily to stay current:

git fetch origin
git rebase origin/main

Long-lived branches are where merge conflicts compound. A branch that's a day old conflicts with almost nothing. A branch that's three weeks old conflicts with everything that shipped in those three weeks.

Step 3: Gate incomplete work behind a feature flag

This is the part that makes trunk-based development possible. Code that isn't ready for users still merges to main — it's just gated.

if (featureFlags.isEnabled('checkout-retry-logic', user)) {
  return retryCheckout(order);
} else {
  return standardCheckout(order);
}

The flag decouples deploy from release. The code ships to production dark. Turning it on for users is a separate, instant, reversible action — no deploy required.

Step 4: Open the PR against main

git push origin feature/checkout-retry-logic

Open the PR through your git host. Required for merge:

  • CI passing (tests, linting, type checks)

  • One reviewer approval

  • No unresolved comments

Keep the PR small enough to review in one sitting. A 40-line PR gets a careful review. A 900-line PR gets a skim and an approve.

Step 5: Merge and delete the branch

Squash merge to keep main's history readable — one commit per feature, not fifteen "wip" commits:

git checkout main
git pull origin main
git merge --squash feature/checkout-retry-logic
git commit -m "Add retry logic for failed checkout requests"
git push origin main
git branch -d feature/checkout-retry-logic
git push origin --delete feature/checkout-retry-logic

Most git hosts (GitHub, GitLab) do this through the PR UI with a "Squash and merge" button — same result, no terminal required.

Step 6: Roll out through the flag, not through git

Deploy ships the code dark. Rollout happens through the flag dashboard:

  1. Enable for internal team first

  2. Enable for 5% of users, watch error rates and metrics

  3. Ramp to 25%, 50%, 100% over hours or days

  4. Remove the flag and the old code path once fully rolled out

If something breaks at any stage, flip the flag off. No revert, no redeploy, no incident response measured in minutes-to-rollback. It's instant.

Handling production fixes

No hotfix branch. A production bug gets the same treatment as any other change:

git checkout main
git pull origin main
git checkout -b fix/checkout-crash-on-empty-cart

Same PR process, same CI gate, same squash merge. Small scope means it moves fast without needing a separate escape hatch. The hotfix branch pattern exists to bypass process — the fix here is having a process that doesn't need bypassing.

What this costs you

Trunk-based development assumes strong CI and a real testing culture. Skip that, and code merges to main broken more often. The feature flag system also becomes a second thing to maintain and eventually clean up — a flag left in the codebase six months after full rollout is dead weight.

Neither cost outweighs what Gitflow charges in return: merge conflict resolution as a recurring tax, release branches that drift from main for weeks, and a mental model where "done" and "deployed" and "released" are three different states instead of one.

Keep Reading