Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Trunk-Based Development vs Git Flow

By Kokil Thapa | Last reviewed: September 2026

Choosing between Trunk-Based Development vs Git Flow is not a style debate. It shapes how often you ship, how painful merges become, and whether production stays stable under pressure. Small teams on a single Laravel app face different trade-offs than an agency running ten client repos with scheduled releases. This guide compares both models with concrete branch rules, CI patterns, and the decision criteria I use on production deployments — including Git branching strategies for real delivery teams.

What Is the Difference Between Trunk-Based Development and Git Flow?

Both models use Git. They differ in branch lifetime, merge targets, and release mechanics.

Trunk-Based Development (TBD) treats one branch — usually main — as the single source of truth. Developers integrate there daily. Feature branches, when used, live for hours or a few days at most. Incomplete work stays hidden behind feature flags or toggles rather than long-lived branches.

Git Flow, popularised by Vincent Driessen's branching model, adds permanent branches: main for production, develop for integration, plus short-lived feature/*, release/*, and hotfix/* branches. Releases are cut from develop, stabilised on release/*, then merged to both main and develop.

Trunk-Based Development vs Git FlowTrunk-Basedmain (trunk)short branchshort branchDaily integrationFeature flags hide WIPGit Flowmaindevelopfeaturefeaturerelease
Trunk-Based Development vs Git Flow — one integration branch versus multiple long-lived branches

The practical split is integration frequency. TBD assumes main is always deployable. Git Flow assumes develop absorbs work until a release window opens.

How Does Git Flow Work in Practice?

Git Flow suits products with numbered releases, compliance sign-off, or client approval gates between builds. I've seen it work on Magento 2 shops and enterprise portals where QA needs a frozen release candidate.

Core branch roles

  • main — production history; every commit is tagged (e.g. v2.4.1).
  • develop — integration branch for the next release.
  • feature/* — branched from develop, merged back to develop.
  • release/* — cut from develop for stabilisation; only bug fixes allowed.
  • hotfix/* — branched from main for urgent production fixes.

Typical Git Flow commands

# Start a feature
git checkout develop
git pull origin develop
git checkout -b feature/booking-calendar

# Finish a feature
git checkout develop
git merge --no-ff feature/booking-calendar
git branch -d feature/booking-calendar

# Cut a release
git checkout -b release/1.8.0 develop
# ... fix release bugs only ...
git checkout main
git merge --no-ff release/1.8.0
git tag -a v1.8.0 -m "Release 1.8.0"
git checkout develop
git merge --no-ff release/1.8.0
git branch -d release/1.8.0

The --no-ff merge preserves branch topology in history. That helps audit trails on regulated projects. It also creates merge commits that some teams find noisy.

Git Flow Release Pipelinefeature/*new workdeveloprelease/*QA freezemainproductionRelease cycle steps1. Merge features into develop2. Cut release branch and run QA3. Tag main and back-merge to develop4. Deploy tagged commit to production
Git Flow moves work through develop and release branches before production tags land on main

On a WooCommerce florist build, Git Flow let staging mirror release/* while develop kept accepting new features. Production only moved when the client signed off the tagged build.

How Does Trunk-Based Development Work in Practice?

Trunk-Based Development keeps integration pain low by making merges small and frequent. The trunk — almost always main — must pass CI on every push. That aligns with how I deploy Laravel apps using Deployer 7 and GitLab CI on shared EC2 hosts.

Rules that actually matter

  1. Integrate to main at least once per developer per day.
  2. Keep feature branches under 48 hours when branches exist at all.
  3. Never commit broken code — use feature flags for incomplete UI.
  4. Run automated tests, lint, and static analysis on every push.
  5. Deploy from main (or a release tag cut from it) after CI passes.

Minimal TBD workflow

# Option A: direct commit (small teams with strong CI)
git checkout main
git pull origin main
# ... make a small change ...
git commit -m "Add rate limit to booking API endpoint"
git push origin main

# Option B: short-lived branch
git checkout -b fix/slug-validation
# ... small scoped change ...
git push origin fix/slug-validation
# Open PR, CI runs, merge same day

Feature flags let you merge incomplete booking logic on a legal-tech portal without exposing it to visitors. The code lives on main; the flag stays off until QA flips it in staging.

Pair TBD with Git hooks and CI automation so broken commits never reach the trunk. Pre-push hooks running PHPUnit and Laravel Pint catch most issues before the pipeline burns minutes.

Trunk-Based CI PipelineCommitsmall diffmaintrunkCI gatetests + lintDeployproductionFailed CI blocks the trunkRevert or fix forward within hoursNo long-lived develop branchFeature flags hide incomplete workDeployer symlink swap after green build
Trunk-Based Development relies on CI gates on main before every production deploy

Sister legal-tech sites on my shared pipeline deploy from main multiple times per week. A green GitLab CI job triggers Deployer, PHP-FPM reloads, and opcache clears. Broken trunk commits get reverted fast — usually within the hour.

Which Git Branching Model Should Your Team Choose?

Neither model wins on ideology alone. Match the workflow to release cadence, team size, and test maturity.

CriterionTrunk-Based DevelopmentGit Flow
Release cadenceDaily to weekly continuous deliveryScheduled versioned releases (weekly to quarterly)
Branch lifetimeHours to 2 daysDays to weeks on feature branches
CI requirementMandatory and fast (< 15 min ideal)Important but release branch absorbs some delay
Team size sweet spot1–15 developers on one codebase5–50+ with dedicated QA and release manager
Incomplete featuresFeature flags or branch by abstractionStay on feature branch until done
Hotfix pathFix on main, deploy immediatelyhotfix/* from main, dual merge
History readabilityLinear or squash-merge preferredMerge commits preserve branch context
RollbackRevert commit or redeploy previous SHARedeploy previous tag (e.g. v1.7.3)

Choose Trunk-Based Development when

  • You deploy Laravel 12 or 13 apps with enterprise application pipelines more than once per month.
  • Your test suite gives confidence within minutes, not hours.
  • Developers sit in one timezone and can coordinate trunk access.
  • You run MVP development and need daily stakeholder demos from production-like staging.

Choose Git Flow when

  • Clients approve fixed release windows — common on client portal projects with document workflows.
  • You ship Magento 2.4.x or WordPress 7.1 themes where store owners expect version numbers.
  • Regulatory or contractual rules require tagged, auditable release artefacts.
  • QA needs a frozen branch while development continues elsewhere.

Hybrid patterns that work

Many teams run trunk-based daily integration with occasional release tags. That is not pure Git Flow. You skip the permanent develop branch. Tag main when marketing announces a version. Hotfixes go straight to main and get cherry-picked if older tags still receive patches.

On Laravel + Livewire booking systems, this hybrid cut merge conflicts during peak season. Daily merges kept the trunk current. Tags marked invoicing milestones for the client.

Branching Model Decision TreeDeploy more than weekly?Yes: strong CI?No: need QA freeze?Trunk-Baseddaily to mainFix CI firstthen adopt TBDGit Flowrelease branchesTrunk-Based Development vs Git Flow — match model to deploy cadence
Decision tree for Trunk-Based Development vs Git Flow based on deploy frequency and CI maturity

What CI and Tooling Do You Need for Each Model?

Branching strategy fails without tooling behind it. A model that looks good on a whiteboard breaks the first time someone force-pushes over a colleague's work.

Trunk-Based Development tooling

Fast CI is non-negotiable. Target sub-15-minute pipelines for Laravel projects on PHP 8.3 or 8.5. Split jobs: lint (Pint, PHPStan), unit tests (PHPUnit), and a smoke deploy to staging.

# .gitlab-ci.yml excerpt — trunk-based Laravel 13 project
stages:
  - test
  - deploy

phpunit:
  stage: test
  script:
    - composer install --no-interaction --prefer-dist
    - cp .env.testing .env
    - php artisan test --parallel

deploy_production:
  stage: deploy
  script:
    - dep deploy production
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  when: on_success

Add secrets scanning in CI before opening the trunk to direct pushes. One leaked API key in a fast-moving repo causes more downtime than a slow release cycle.

Git Flow tooling

Git Flow benefits from branch protection rules per branch type. Protect main and develop. Require PR reviews on features. Allow only maintainers to merge release/*.

The git-flow extension wraps branch creation and merges:

git flow init
git flow feature start payment-webhook
git flow feature finish payment-webhook
git flow release start 2.1.0
git flow release finish 2.1.0

Document which branches map to which environments. Staging tracks develop. Pre-production tracks release/*. Production tracks tagged commits on main.

Merge strategy notes

TBD teams often prefer squash merges or rebase to keep history linear. Git Flow teams use merge commits to preserve branch boundaries. Read Git rebase vs merge before mandating either — the wrong default creates silent conflict debt.

Use the JSON formatter tool when debugging CI webhook payloads from GitLab or GitHub. Misconfigured pipeline rules are a common reason "trunk-based" devolves into de facto Git Flow with a renamed develop branch.

What Are Common Mistakes When Adopting Trunk-Based Development or Git Flow?

Teams often adopt labels without changing habits. Calling develop "trunk" does not make it trunk-based.

Trunk-Based Development anti-patterns

  • Long-lived "short" branches — a two-week feature branch defeats the model. Split the work or use flags.
  • Weak CI — merging to main without tests turns the trunk into a shared junk drawer.
  • No revert culture — teams that debate for days on a broken commit lose TBD's main benefit.
  • Friday afternoon merges — if nobody monitors production over the weekend, batch risky changes early in the week.

Git Flow anti-patterns

  • Permanent drift between main and develop — forgotten back-merges from release branches cause nasty conflicts.
  • Feature branches from main — breaks the model and skips integration testing on develop.
  • Release branch feature creep — "just one small addition" on a frozen release destroys QA confidence.
  • Too many parallel release branches — supporting three active releases without automation burns hours.

I've recovered lost work with Git reflog after a botched Git Flow merge. The tool saved the day. The process still needed fixing.

For Nepal-based agencies juggling multiple client repos, standardise one model per repo but do not force one model across every stack. A Shopify theme client may want tagged releases. An internal Laravel admin panel should run trunk-based with daily deploys via Linux CI runners.

Key Takeaways

  • Trunk-Based Development optimises for small, frequent integrations to main with CI as the safety net.
  • Git Flow optimises for versioned releases with a dedicated integration branch and QA freeze windows.
  • Pick TBD when you deploy weekly or faster and your test pipeline finishes in minutes.
  • Pick Git Flow when clients or compliance require tagged, approved release candidates.
  • Feature flags make TBD practical for incomplete features; long branches make Git Flow tolerable for large teams.
  • Hybrid tagging on a single trunk beats a ceremonial develop branch most SMEs never fully maintain.

People Also Ask

Can small teams use Git Flow?

Yes, but it is often overhead. A two-person Laravel shop rarely needs develop, release/*, and tagged hotfix branches. Simpler TBD with occasional tags covers most SME projects described in guides on website development for SMEs in Nepal.

Is Trunk-Based Development the same as Continuous Deployment?

Not exactly. TBD is a branching discipline. Continuous Deployment is an automated release step after CI passes. You can practice TBD and still deploy manually on Fridays. Many teams integrate to main daily but promote to production on a schedule.

Does Git Flow work with monorepos?

It can, but release coordination gets harder. Trunk-Based Development with path-filtered CI jobs scales better for monorepos because every commit touches shared integration sooner. Large organisations sometimes use release branches per service instead of one global Git Flow.

What branch should Laravel projects use in 2026?

Most Laravel 12 and 13 applications I maintain use main as trunk with GitLab CI and Deployer 7. Client-facing portals with formal UAT gates — like work covered in legal-tech portfolio builds — may add short release branches without full Git Flow ceremony. Match the branch model to the client's approval process, not the framework version.

Pick the Model Your Deploy Cadence Already Proves

Trunk-Based Development vs Git Flow comes down to one question: how often can you honestly ship tested code to production? If the answer is daily or weekly, invest in CI and adopt trunk-based habits. If releases need QA sign-off and version numbers, Git Flow — or a trimmed hybrid — earns its merge commits.

Start by auditing your last three months of merges. Count branch lifetimes and production deploy frequency. The data usually makes the decision obvious. For help designing CI pipelines, deployment workflows, or web development delivery that matches your branching model, contact us — or explore related writing on Laravel development practices and ongoing support and maintenance.

Authoritative references: the Git branching workflows chapter in the official Pro Git book, Atlassian's Git Flow workflow guide, and the patterns described at trunkbaseddevelopment.com.

Frequently Asked Questions

Trunk-Based Development treats one branch, usually main, as the single source of truth. Developers integrate there daily through direct commits or feature branches lasting hours to two days at most. Incomplete work stays off production using feature flags rather than long-lived branches.

Git Flow is Vincent Driessen's branching model with permanent main and develop branches plus short-lived feature, release, and hotfix branches. Releases are cut from develop, stabilised on release branches, tagged on main, then merged back to develop.

No. Trunk-Based Development is a branching discipline about frequent integration to main. Continuous Deployment is an automated step that promotes passing CI builds to production. You can integrate to main daily and still deploy manually on a schedule.

Both use Git but differ in branch lifetime, merge targets, and release mechanics. Trunk-Based Development assumes main is always deployable with integration at least once per developer per day. Git Flow routes work through a permanent develop branch and release branches before production tags land on main. The practical split is integration frequency versus scheduled, versioned release windows with QA freeze periods.

Choose Trunk-Based Development when you deploy Laravel 12 or 13 apps more than once per month, your test suite finishes in minutes, developers can coordinate trunk access, or you need daily stakeholder demos from production-like staging. It suits teams of one to fifteen developers on one codebase with mandatory, fast CI under fifteen minutes. I've used this on legal-tech sister sites deploying from main multiple times per week via GitLab CI and Deployer 7.

Git Flow fits products with numbered releases, compliance sign-off, or client approval gates between builds. Choose it when clients approve fixed release windows, you ship Magento 2.4.x or WordPress 7.1 themes where owners expect version numbers, regulatory rules require tagged auditable artefacts, or QA needs a frozen branch while development continues. I've seen it work on WooCommerce florist builds where staging mirrored release branches until the client signed off the tagged build.

Developers branch feature branches from develop and merge back with no-fast-forward merges to preserve audit trails. To cut a release, create release/x.y.z from develop, allow only bug fixes, merge to main with a version tag, then merge back to develop and delete the release branch. Hotfix branches start from main for urgent production fixes and merge to both main and develop. The git-flow extension wraps these steps with commands like git flow feature start and git flow release finish.

Keep main as the trunk and integrate at least once per developer per day. Use direct commits for small teams with strong CI, or short-lived branches merged the same day after pull request review. Never commit broken code to main; hide incomplete booking logic or UI behind feature flags until QA enables them in staging. Pair the model with pre-push hooks running PHPUnit and Laravel Pint, plus CI gates on every push before Deployer 7 production deploys and PHP-FPM reloads.

Yes, but it is often unnecessary overhead. A two-person Laravel shop rarely needs permanent develop, release, and hotfix branches with tagged hotfix ceremonies. Simpler Trunk-Based Development with occasional release tags covers most SME projects, including the kind of website development work common for small businesses in Nepal. If your client does not require frozen release candidates or versioned sign-off, the branch topology costs more than it saves.

It can, but release coordination gets harder when many services share one repository. Trunk-Based Development with path-filtered CI jobs scales better for monorepos because every commit integrates to shared main sooner rather than sitting on long-lived develop branches. Large organisations sometimes use release branches per service instead of one global Git Flow model across the entire monorepo.

Most Laravel 12 and 13 applications I maintain use main as trunk with GitLab CI and Deployer 7 on shared EC2 hosts. Client-facing portals with formal UAT gates, such as legal-tech builds with document workflows, may add short release branches without full Git Flow ceremony. Match the branch model to the client's approval process and deploy cadence, not the framework version alone.

Fast CI is non-negotiable. Target sub-fifteen-minute pipelines for Laravel on PHP 8.3 or 8.5 with split jobs for lint using Pint and PHPStan, unit tests via PHPUnit, and a smoke deploy to staging. Protect main with branch rules so only green pipelines deploy production via Deployer. Add secrets scanning in CI before allowing direct trunk pushes. Pre-push Git hooks catch most issues locally before the pipeline burns minutes on broken commits.

Git Flow benefits from branch protection rules per branch type. Protect main and develop, require pull request reviews on feature branches, and restrict release branch merges to maintainers. Document which branches map to environments: staging tracks develop, pre-production tracks release branches, production tracks tagged commits on main. The git-flow extension standardises branch creation and finishing. Misconfigured pipeline rules are a common reason trunk-based labels devolve into de facto Git Flow with a renamed develop branch.

Teams often adopt the label without changing habits. Anti-patterns include long-lived feature branches lasting two weeks, weak CI that merges untested code to main, no revert culture that debates broken commits for days, and Friday afternoon merges when nobody monitors production over the weekend. Calling develop your trunk does not make the workflow trunk-based. Split large work into smaller integrations or use feature flags instead of parking incomplete code on branches.

Permanent drift between main and develop from forgotten back-merges causes nasty conflicts during release finishes. Branching features from main instead of develop skips integration testing on develop. Adding new features to a frozen release branch destroys QA confidence. Supporting three parallel active release branches without automation burns hours every week. I've recovered lost work with Git reflog after a botched merge, but the process still needed fixing regardless of the tooling rescue.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: