The way developers work with Git — how they branch, merge, and deploy code — has changed dramatically over the last decade. GitFlow is best for versioned software with multiple supported releases, GitHub Flow works well for web apps with continuous deployment, and Trunk-Based Development is what high-performing teams with strong test automation should aspire to. Understanding why these changes happened will help you make much better decisions for your own team.
If you’ve ever merged code on a Friday afternoon and immediately regretted all your life choices, you know exactly what I’m talking about. That usually happens when your team has no real branching strategy — or worse, the wrong one for what you’re trying to achieve.
I’ve been part of teams that used GitFlow religiously, teams that adopted GitHub Flow, and teams that went all-in on Trunk-Based Development. Trust me, picking the wrong workflow for your project creates so much unnecessary friction that your developers end up fighting Git instead of shipping features.
In this article, I’ll break down the three main Git workflows that teams use today: GitFlow, GitHub Flow, and Trunk-Based Development. I’ll look at how they evolved, why they exist, and most importantly, when each one actually makes sense for your specific project.
Let’s get into it.
Why Git Workflows Even Matter
When Git was created by Linus Torvalds in 2005, it was designed to be extremely flexible. You could basically do whatever you wanted with branches. Create ten branches for a single feature? Sure. Merge directly to main without any review? Go ahead. Keep a branch alive for six months? Git doesn’t care.
That’s great for freedom but terrible for consistency across teams.
So teams started creating conventions — agreed-upon ways of working — so that everyone would follow the same process. This made collaboration easier, code reviews more predictable, and deployments less stressful. According to the 2024 DORA State of DevOps Report, teams with well-defined workflows show significantly better software delivery performance across all four key metrics.
But here’s where it gets interesting. The right workflow for your team depends entirely on what you’re building and how you’re deploying it.
Are you building a mobile app that users download and install, where you need to support multiple versions running in the wild? Or are you building a web application that deploys continuously to production multiple times a day?
These two scenarios require completely different approaches. That’s exactly why these different workflows exist.
What Is GitFlow? The Structured Approach (And Why It’s Often Overkill)
GitFlow is a Git branching model that uses multiple long-lived branches — main, develop, feature, release, and hotfix — to manage parallel development and versioned software releases. It was introduced by Vincent Driessen in January 2010, and for many years it became the branching model that everyone talked about. I personally used GitFlow in many projects in my earlier engineering days.
The idea behind GitFlow is that you have multiple long-lived branches, each serving a specific purpose:
- Main branch — Production-ready code that’s deployed to live servers
- Develop branch — Work in progress, used for integration before releases
- Feature branches — New work, one branch per feature (e.g.,
feature/user-authentication) - Release branches — Preparing deployments, final testing and bug fixes
- Hotfix branches — Emergency fixes on production (e.g.,
hotfix/payment-bug)
A Real-World GitFlow Scenario
Let’s say you’re building a desktop application for enterprise customers. Your users are running different versions — some on version 2.3, some on 2.4, some have already upgraded to 3.0. This is common in industries like healthcare and finance, where enterprises often run 2-3 major versions concurrently due to compliance requirements.
Now your product manager comes to you and says, “We need to fix a critical bug in version 2.3, but we’re already working on version 3.0.”
With GitFlow, this is actually straightforward:
- Create a hotfix branch from the tag where version 2.3 was released
- Fix the bug
- Merge it back to both
mainanddevelop - Release version 2.3.1
The fix goes into the current production version and into future releases. Get the point?
When GitFlow Makes Sense
- Software that ships in versions — Desktop applications, mobile apps, enterprise software that customers install on their own infrastructure. Think Electron apps, iOS/Android apps, or software with installers.
- Supporting multiple versions simultaneously — If you’re maintaining version 2.x while developing version 3.x, GitFlow gives you the structure to handle that. Teams supporting 3+ concurrent versions benefit most.
- Large teams needing clear structure — Having explicit branches for releases and hotfixes can prevent chaos when you have 20+ developers. In my experience, teams of 50+ developers almost always need this level of structure.
- Regulated industries — Healthcare, finance, government — where every change needs approval, audit trails, and traceability
Why GitFlow Is Often Overkill for Modern Web Apps
Here’s the thing — GitFlow has serious downsides, which is why most modern teams building web applications don’t use it anymore. A 2023 JetBrains Developer Survey found that only about 22% of teams still use GitFlow, down from its peak adoption.
It slows you down. All that branch management — creating release branches, merging hotfixes back to develop, managing long-lived feature branches — adds massive overhead. Your team ends up spending more time managing branches than shipping features.
I’ve seen teams where developers spent 20% of their time just resolving merge conflicts because their feature branches had diverged from develop for weeks. Studies show merge conflict resolution can consume 10-25% of developer time in branch-heavy workflows.
It doesn’t play well with continuous delivery. If you want to deploy to production multiple times a day, having all these long-lived branches creates integration headaches. You’re constantly dealing with merge conflicts because people’s work has diverged for too long.
Even the creator says don’t use it for web apps. Vincent Driessen himself updated his original blog post in 2020 to say: “If you’re doing continuous delivery, you should probably use a simpler workflow.”
That’s like the inventor of the fax machine telling you to use email instead.
What Is GitHub Flow? The Minimalist Approach
GitHub Flow is a lightweight branching workflow built around a single rule: anything in the main branch is always deployable. It emerged as a much simpler alternative to GitFlow. If GitFlow is a five-course meal, GitHub Flow is a really good sandwich. Simple, fast, gets the job done.
As GitHub’s official documentation describes it, the core principle is beautiful in its simplicity: Anything in the main branch should always be deployable. That’s it. One rule.
Here’s how it works:
- Create a branch from
main - Make your changes
- Open a pull request
- Get it reviewed by your team
- Merge to
main - Deploy immediately
Real-World Scenario
It’s Tuesday morning. You notice users can’t upload profile pictures in your web application. Here’s what happens:
git checkout -b fix/profile-uploadYou find the bug in your file upload service, fix it, push the branch:
git add .git commit -m "fix: handle null content-type in profile upload"git push origin fix/profile-uploadYou open a PR, your colleague reviews it over coffee, approves it, you merge to main — and your CI/CD pipeline deploys the fix. It’s live in production by lunchtime. According to GitHub’s internal data, the median time from PR open to merge across their platform is about 6 hours for teams using GitHub Flow effectively.
That’s the speed GitHub Flow enables.
When GitHub Flow Makes Sense
- Web applications that deploy continuously — APIs, web apps, any SaaS product where there’s only one version in production. If you’re building RESTful APIs, this is likely your best bet.
- Small to medium-sized teams that move fast — You don’t need GitFlow’s complexity when you have 5-15 developers. Teams in this range typically merge 3-10 PRs per day with GitHub Flow.
- Solid automated testing and CI/CD pipelines — If
mainis always deployable, you need confidence that problems will be caught. This means good unit tests, integration tests, and automated deployments with tools like GitHub Actions, GitLab CI, or Jenkins. - When you want to ship features instead of managing branches — Because let’s be honest, managing Git branches is not why any of us became developers
The Challenges
- Doesn’t handle multiple versions — Everything goes straight to production. If you need to support v2 and v3 simultaneously, this workflow won’t help you.
- Demands discipline — If someone merges bad code and
mainbreaks, your entire deployment pipeline stops. Everyone feels that pain immediately. Writing clean, well-tested code becomes a non-negotiable habit. - PR reviews can become bottlenecks — When everyone needs code reviewed before merging, queues build up. I’ve seen teams where PRs sit for 2-3 days waiting for review, which defeats the purpose of a “fast” workflow. Data from LinearB shows the average PR wait time across the industry is about 24 hours.
- Can struggle with multiple teams — When you have three teams merging to
mainconstantly, coordination becomes harder without good communication.
The ugly truth: GitHub Flow assumes your team already has good habits. If your team treats pull requests like optional suggestions and testing like homework they forgot to do, you’re going to have problems.
What Is Trunk-Based Development? The High-Performance Approach
Trunk-Based Development (TBD) is a branching strategy where all developers commit to a single shared branch (main/trunk) at least once a day, using feature flags to manage incomplete work in production. This is my favorite and what high-performing DevOps teams are increasingly moving toward. Research from the DORA metrics consistently shows that elite teams use Trunk-Based Development.
With Trunk-Based Development (TBD), some teams commit straight to main. Others use temporary branches that exist for maybe half a day before merging. The key principle is the same: integrate continuously. As trunkbaseddevelopment.com documents, the maximum branch lifetime should be one to two days — anything longer defeats the purpose.
How It Actually Works
Let’s say three developers are working on different parts of a checkout feature for your e-commerce API. They’re all committing to main multiple times a day — typically 5-10 commits per developer per day.
“But wait,” you’re thinking, “they’re committing half-done features to main?”
Here’s the clever part: Trunk-Based Development uses feature flags — switches that turn features on or off. This is one of those essential practices for senior developers that fundamentally changes how you ship code.
Here’s the basic pattern in any language:
// Pseudocode - works the same in any languageasync function processCheckout(order) { if (await featureFlags.isEnabled("NewCheckoutFlow")) { return await processNewCheckout(order); } return await processLegacyCheckout(order);}The incomplete checkout code is in production, but it’s hidden from users because the flag is disabled. Tools like LaunchDarkly, Unleash, or even simple environment variables can manage these flags.
A word of caution: Feature flags are powerful but require discipline. Old flags that never get cleaned up become technical debt. A typical team accumulates 5-10 stale flags per quarter if they don’t actively prune them. Make it a habit to remove flags once a feature is fully rolled out — otherwise you end up with spaghetti code full of conditional branches that nobody understands anymore.
Every small commit triggers automated tests. By Friday, the feature is complete. They flip the flag in their feature flag service, and the new checkout is live.
The impact? Zero merge conflicts because they’ve been integrating continuously all week. Automated tests have been checking every small change, giving developers fast feedback loops.
When TBD Shines
- Experienced, disciplined developers — They don’t have to be senior, just disciplined and write clean code. Mid-level developers who understand testing and small commits work great. Teams can start TBD with as few as 3 developers who share this discipline.
- Bulletproof automated testing — This is non-negotiable. If you’re continuously deploying, you need extensive tests. Unit tests, integration tests, maybe even contract tests. No shortcuts here. Most successful TBD teams maintain 70%+ code coverage as a baseline.
- Rapid integration and faster deployment — Research from DORA metrics consistently shows elite teams (who typically use TBD) significantly outperform others. The 2018 Accelerate research found elite teams deploy 46x more frequently with 5x faster lead time, while 2024 data shows gaps as large as 182x in deployment frequency and 127x faster change lead times.
- SaaS products with one version in production — If you’re building a web service that serves customers from the cloud, TBD is probably your best option. Companies like Google, Meta, and Netflix all use variants of TBD.
The Challenges
Problems surface faster. If your tests don’t catch bad code, you’ll know about it quickly. Some see this as a risk, but it’s actually a feature — weak spots in your pipeline become obvious immediately. You need proper guardrails though — CI checks that block merging on test failures, code review requirements, maybe even branch protection rules.
Weak test coverage means chaos. But this isn’t always bad — it immediately exposes that weakness. I’ve seen teams adopt TBD and within a week realize their test coverage was embarrassingly low. That pain forced them to fix it.
Requires a cultural shift. Developers need to learn to make smaller commits, use feature flags, understand continuous integration. It’s not just technical, it’s a mindset change. Some developers resist this — they like their feature branches that live for two weeks. Expect 2-4 weeks of adjustment when transitioning from GitFlow or GitHub Flow.
The ugly truth: Trunk-Based Development feels reckless until you realize it forces you to build the automated testing you should have had anyway. It’s like removing training wheels — scary at first, but faster once you get it.
How Did Git Workflows Evolve?
GitFlow made perfect sense in 2010. Back then, most software shipped in versions. You released 1.0, then worked on 2.0 for months. Deployment was risky, manual, and infrequent. Teams deployed maybe once a quarter — the 2014 Puppet State of DevOps Report found most organizations deployed less than once per month.
Then something changed. The rise of SaaS and continuous delivery. Companies like Amazon (deploying every 11.6 seconds as of 2015), Netflix, and Spotify started deploying to production multiple times a day. They weren’t shipping versions — they were shipping features continuously.
GitFlow couldn’t keep up. All those long-lived branches, all that merging overhead — it was too slow for teams that wanted to deploy ten times a day.
So teams started simplifying. GitHub Flow emerged as a faster, leaner alternative.
But even GitHub Flow had limitations. Pull requests could become bottlenecks. Branches could live too long, especially when reviews got delayed.
That’s where Trunk-Based Development came in. By committing directly to main or using very short-lived branches, teams could integrate continuously and deploy faster than ever.
This evolution only made sense because the underlying technology improved:
- Automated testing is now mature and fast
- CI/CD pipelines are easy to build with GitHub Actions, GitLab CI, CircleCI, Jenkins
- Feature flags are a solved problem with tools like LaunchDarkly, Unleash, or ConfigCat
- Containerization with Docker makes deployments predictable
- Cloud platforms like Azure and AWS make rollbacks trivial — with infrastructure automation tools like Terraform, you can redeploy in minutes
The evolution isn’t just about workflows — it’s about the entire ecosystem of tools and practices that support them.
Can You Combine Git Workflows? Hybrid Approaches
Here’s something interesting: many teams use hybrid approaches. The textbook workflows rarely exist in pure form. About 60% of teams in practice use some form of hybrid, adapting the core workflows to their specific needs.
- TBD with release branches — Committing to
mainfrequently, but creating release branches for stability when you need to prepare a major release - TBD with PR requirements for external teams — Core team commits directly, external contributors or contractors use pull requests for an extra layer of review
- GitHub Flow with feature flags — Getting some TBD benefits (like deploying incomplete features safely) without going all-in on trunk-based commits
These hybrid approaches show you can mix strategies based on your project’s needs, team structure, and maturity level. How you structure your architecture and organize your modules often influences which workflow — or hybrid — works best. Don’t feel like you need to follow a workflow exactly as described.
Practical Tips for Your Team
1. Automate Everything
No matter which workflow you choose, automation is your friend. Set up CI/CD pipelines for:
- Running tests on every PR
- Code formatting and linting
- Security scanning with tools like Snyk, Dependabot, or OWASP dependency check
- Automatic deployment to staging environments
2. Document Your Process
Write down your branching strategy, commit message conventions (I recommend Conventional Commits), code review expectations. Create a CONTRIBUTING.md in your repo. Don’t assume everyone knows the rules.
3. Measure Your Performance
Track metrics like:
- Deployment frequency — How often do you ship? Elite teams deploy on demand, multiple times per day.
- Lead time for changes — How long from commit to production? Elite teams achieve less than one day; low performers take 1-6 months.
- Time to restore service — When things break, how fast do you recover? Elite teams restore within one hour.
- Change failure rate — What percentage of deployments cause problems? Elite teams keep this between 0-5%.
These DORA metrics show clearly if your workflow is making your team faster or slower.
4. Start Simple, Then Evolve
If you’re unsure, start with GitHub Flow. It’s the easiest to understand and implement. As your team matures, as your test coverage improves, you can gradually move toward Trunk-Based Development. Check the .NET developer roadmap for a broader view of skills that support these practices.
Your workflow should evolve as your team evolves. Don’t get stuck using GitFlow just because that’s what you learned five years ago.
Troubleshooting Common Git Workflow Issues
Long-Lived Feature Branches Causing Merge Conflicts
If your feature branches live longer than 2-3 days, merge conflicts become inevitable. The fix: break large features into smaller, independently deployable chunks. Use feature flags to hide incomplete work. Merge to main at least once per day, even if the feature isn’t done yet. If you’re already drowning in conflicts, do a fresh rebase from main and commit to shorter branch lifetimes going forward.
Broken Main Branch Blocking All Deployments
When main breaks, everything stops. Prevention is better than cure — enforce CI checks that block merging on test failures, require at least one approval on PRs, and run integration tests in your pipeline. If main is already broken, revert the offending commit immediately (git revert), then fix the issue in a new branch. Never try to “fix forward” under pressure.
PR Review Bottlenecks Slowing Delivery
When PRs sit for days waiting for review, your workflow is broken regardless of which model you use. Solutions: set a team SLA (e.g., review within 4 hours), use smaller PRs (under 400 lines of diff), rotate reviewers on a schedule, and use draft PRs to signal “not ready yet.” Some teams assign a “review buddy” each day whose primary job is clearing the PR queue.
Feature Flag Cleanup and Technical Debt
Stale feature flags accumulate fast. After 3-6 months, nobody remembers what half of them do. Fix this by adding an expiry date to every flag when you create it. Track flags in a shared spreadsheet or your project management tool. Schedule monthly flag cleanup sessions. If a flag has been enabled for everyone for more than two weeks, remove the conditional and delete the flag.
Hotfix Process Confusion Between Workflows
Teams often panic during production incidents because their hotfix process isn’t clear. Document your hotfix process explicitly — who can approve, which branch to base it on, whether it skips code review. In GitFlow, hotfixes branch from main and merge back to both main and develop. In GitHub Flow and TBD, hotfixes are just high-priority PRs to main with expedited review.
Team Resistance When Changing Workflows
Changing workflows is as much about culture as tools. Start with a pilot — one team or one project — rather than a company-wide mandate. Show concrete metrics (deployment frequency, lead time) before and after. Give developers 2-4 weeks to adjust, and expect productivity to dip temporarily before it improves. Pair experienced TBD practitioners with newcomers for the first sprint.
What is the difference between GitFlow and GitHub Flow?
GitFlow uses multiple long-lived branches (main, develop, feature, release, hotfix) designed for software that ships in versioned releases. GitHub Flow uses only one long-lived branch (main) with short-lived feature branches, designed for continuous deployment where only one version is in production. GitFlow was introduced in 2010 for versioned software; GitHub Flow emerged later as a simpler alternative for web applications that deploy continuously.
What is Trunk-Based Development?
Trunk-Based Development (TBD) is a branching strategy where all developers commit to a single shared branch (main/trunk) at least once a day, using feature flags to manage incomplete work in production. DORA research consistently shows elite-performing teams use TBD, achieving up to 182x more frequent deployments and 127x faster change lead times compared to low performers.
Which Git workflow is best for small teams?
For small teams of 2-15 developers building web applications, GitHub Flow is the best starting point. It's simple, fast, and requires minimal branch management overhead. As the team matures and builds strong test automation, they can evolve toward Trunk-Based Development for even faster delivery. GitFlow is typically overkill for small teams unless they're shipping versioned software.
When should I use GitFlow over GitHub Flow?
Use GitFlow when you need to support multiple software versions simultaneously — such as desktop applications, mobile apps, or enterprise software where customers run different versions. GitFlow is also better for regulated industries (healthcare, finance) that require formal release processes and audit trails. If you're building a web app with one version in production, GitHub Flow or Trunk-Based Development is a better fit.
What are the DORA metrics for software delivery?
The four DORA metrics are: deployment frequency (how often you ship), lead time for changes (commit to production), time to restore service (how fast you recover from failures), and change failure rate (percentage of deployments causing problems). Elite teams deploy on demand (multiple times per day), have lead times under one day, restore service within one hour, and maintain a 0-5% change failure rate.
How do feature flags work with Trunk-Based Development?
Feature flags are conditional switches that enable or disable features in production code. In TBD, developers commit incomplete work to main behind disabled feature flags, so the code is deployed but hidden from users. When the feature is complete and tested, the flag is enabled. This eliminates the need for long-lived feature branches. Common tools include LaunchDarkly, Unleash, and ConfigCat. Important: always remove stale flags to avoid technical debt.
Can I combine Git workflows in a hybrid approach?
Yes, about 60% of teams use hybrid approaches. Common combinations include: TBD with release branches for major releases, TBD with PR requirements for external contributors, and GitHub Flow with feature flags for safer deployments. The key is adapting the workflow to your team's needs rather than following any model rigidly. Start with the closest matching workflow and adjust based on your deployment model and team structure.
How do I migrate from GitFlow to Trunk-Based Development?
Migrate incrementally: (1) Shorten feature branch lifetimes to 1-2 days maximum, (2) introduce feature flags for incomplete work, (3) invest heavily in automated testing — aim for 70%+ code coverage, (4) eliminate the develop branch by merging directly to main, (5) remove release branches if you deploy continuously. Start with a pilot team, measure DORA metrics before and after, and expect a 2-4 week adjustment period.
Summary
| Workflow | Best For | Avoid When |
|---|---|---|
| GitFlow | Versioned software, multiple supported versions, regulated industries | Web apps, continuous deployment, small teams |
| GitHub Flow | SaaS, web apps, small-medium teams, continuous deployment | Multiple versions, large teams without discipline |
| Trunk-Based | High-performing teams, extensive testing, rapid deployment | Weak test coverage, inexperienced teams, no CI/CD |
Key Takeaways
- GitFlow is best for versioned software, multiple supported releases, and regulated industries — but it’s overkill for most modern web applications.
- GitHub Flow is the ideal starting point for small-to-medium teams (5-15 developers) building continuously deployed web applications.
- Trunk-Based Development is what elite-performing teams use — DORA data shows up to 182x more frequent deployments and 127x faster lead times — but it requires strong test automation and feature flag discipline.
- Optimize for speed of feedback: the faster code moves from a developer’s machine to production, the faster your team learns and improves. That usually means simpler workflows, not more complex ones.
- Start with GitHub Flow, evolve toward TBD: invest in automated testing, adopt feature flags, shorten branch lifetimes, and measure your DORA metrics to track progress.
What Git workflow does your team use? Is it working for you? Let me know in the comments below.
Happy Coding :)


