Many organisations talk about CI/CD, but the reality is that most have achieved continuous integration (CI) without continuous deployment (CD). Embracing both CI and CD represents a fundamental shift in how software reaches production and how teams approach risk, quality and delivery.
This blog, adapted from a Tech Talk by Principal Software Engineers Luke Mitchell and Akeel Ahmed, explores two distinct pathways to achieving true continuous deployment: trunk-based development with ephemeral environments, and Git Flow with structured release management. Both approaches can deliver frequent, reliable releases, but they require different technical infrastructure, and cultural and organisational readiness.
The Current State of Continuous Deployment
Continuous integration has become standard practice through automated testing, code reviews and build pipelines. However, the journey from merged code to production often remains batched and infrequent.
The reasons are varied: legacy approval processes inherited from waterfall methodologies, lack of confidence in automated testing, concerns about deployment risk or simply the complexity of managing multiple environments. Yet the benefits of genuine continuous deployment – faster feedback loops, reduced integration risk and the ability to respond rapidly to business needs – make it worth pursuing.
Trunk-Based Development
At the core of trunk-based development is a single principle: the main branch should always be in a deployable state.

The Fundamentals
Unlike Git Flow's multiple long-lived branches, trunk-based development maintains a single main branch. Developers work on short-lived feature branches, typically lasting hours or days rather than weeks, before merging back to main. Each merge triggers an automated pipeline that can deploy directly to production.
This approach demands discipline. Small, focused commits become essential. Code reviews must happen synchronously – within 10 to 15 minutes of raising a pull request. The entire team must prioritise getting code through the pipeline over starting new work.
Ephemeral Environments
One of the most powerful enablers of trunk-based development is the use of ephemeral environments. Rather than maintaining static QA and staging environments where multiple developers' changes intermingle, each feature branch spawns its own temporary environment.
When a developer pushes their branch, the pipeline automatically provisions cloud infrastructure and deploys their changes to an isolated environment. This provides several advantages:
Isolation of changes: Bugs discovered during testing are definitively linked to the development stage.
Parallel development: Developers and testers can work simultaneously without interference, removing bottlenecks from the development and QA processes.
Cost efficiency: Environments are taken down automatically after the code merges to main, ensuring resources are only consumed when needed.
Production parity: Each ephemeral environment can mirror production configuration, reducing environment-specific issues.
The workflow is streamlined: Development happens on the feature branch, code review occurs when the developer opens a pull request, QA testing happens in the ephemeral environment once the PR is approved, and upon successful testing, the code merges to main and the ephemeral environment is deleted.
Release Strategy for Trunk-based Development
Merging to main doesn't necessarily mean immediate production deployment, though it could. Many teams create release candidate branches automatically upon merge to main. These branches can then be deployed to UAT or production based on business requirements.
Teams take different approaches to deployment timing. Some deploy every merge to production immediately – true continuous deployment. Others batch a few tickets together, deploying the most recent release candidate branch that contains all the desired changes. The key principle remains constant: all code in main is production-ready, and the organisation decides when to deploy based on business needs, not technical readiness.
To track what's currently live, many teams maintain a production branch, merging their release candidate branches into it after deployment. This provides a valuable snapshot of the live environment, simplifying rollbacks and hotfixes by maintaining a known good state to return to. Teams requiring additional safeguards sometimes create rollback candidate branches automatically before each production deployment, though this adds complexity that not all teams need.
Feature flags provide an additional layer of deployment control that works with both trunk-based development and Git Flow. They're particularly valuable in trunk-based development, where code deploys to production frequently, by controlling feature visibility independently of code deployment.
The Benefits
- Risk mitigation: pinpointing bugs becomes easier in smaller, recent releases.
- Early client/user feedback: a clients’ vision can change or become clearer when presented with something concrete – it’s best to know as early as possible.
- Reactive to change: small releases reduce the amount of time and difficulty it takes to get feedback and implement changes.
The Cultural Requirements
Trunk-based development requires significant cultural change. It demands trust that developers will maintain quality, that automated tests are comprehensive and that the team will respond quickly to production issues.
It also requires scaling back bureaucratic approval processes. Change Advisory Boards can be antithetical to continuous deployment if every change is scrutinised. The governance must shift from manual approval gates to automated quality gates and rapid response capabilities.
Full team ownership becomes paramount. From junior developers to tech leads, everyone shares responsibility for production stability. This shared accountability, combined with the practice of deploying small changes frequently, reduces risk compared to large, infrequent releases.
Git Flow
Not every organisation can adopt ephemeral environments immediately. Infrastructure constraints, compliance requirements or existing tooling may necessitate static environments. Git Flow provides a structured approach to continuous deployment within these constraints.
The Git Flow Model

Git Flow employs multiple long-lived branches with specific purposes:
- Main reflects production and is updated only with tested, stable releases.
- Release branches are cut from develop to deploy to production.
- Develop serves as the integration branch for ongoing development.
- Feature branches are created from develop for new functionality.
- Bugfix branches are short-lived branches created from develop or release to fix defects, and are merged back into their source branch once resolved.
- Hotfix branches are created from main for urgent production fixes, and merged back into main and develop.
This structure provides clear separation between development, testing and production code. Whilst feature branches can be short-lived with good continuous integration practices, the methodology naturally supports more structured release cycles.
Release Planning and Management
Success with Git Flow depends heavily on release planning and management. Rather than ad-hoc deployments, teams batch related user stories into planned releases. This upfront planning – tagging stories with release identifiers early in the sprint – provides predictability for stakeholders whilst still enabling frequent releases.
The workflow operates in distinct phases:
Development phase: Developers merge feature branches to develop, which automatically deploys to a shared QA environment for testing.
Release preparation: When all features for a release are complete and QA-tested, a release branch is created from develop.
UAT phase: The release branch is deployed to UAT for stakeholder testing. Crucially, no new features are added during this phase – only bug fixes and refinements.
Production deployment: After successful UAT, the release branch deploys to production and merges back to main, providing a live reflection of production in the codebase.
Managing Hotfixes
Git Flow excels at handling production issues whilst development continues. Hotfix branches are created from main, tested independently, and deployed to production without disrupting the develop branch or ongoing releases.
A practical versioning approach helps manage this: if release 1.0 is in production and a bug is discovered, create hotfix branch 1.1, deploy it to production, then merge it back to both main and develop to keep everything aligned.
The Advantages of Structure
Git Flow's structure provides several benefits for teams and stakeholders:
Stability: The main branch always reflects production, reducing confusion about what code is live.
Visibility: Clear branching structure makes it easy to understand what features are in which release.
Control: Product owners and project managers have explicit control over what gets released and when.
Transparency: Every merge, tag and deployment is logged, providing an audit trail for accountability.
This structure particularly benefits larger teams where multiple developers work on the same codebase simultaneously. The isolation between branches provides clearer separation of concerns and reduces the risk of unstable code reaching production.
Choosing Your Approach
In a simple analogy, trunk-based development can be imagined as multiple passengers in different taxis heading to the same destination, whereas Git Flow involves a group of passengers on a bus – going through each checkpoint together. The decision between the two strategies depends on infrastructure capabilities and business requirements.

Trunk-Based Development Fits When:
- You have cloud infrastructure that supports ephemeral environments
- Your team is comfortable with high deployment frequency
- Automated testing provides high confidence
- There's organisational trust in the development team
- Small, incremental releases align with business needs
- You want to minimise the feedback loop between development and production
Git Flow Fits When:
- You have static environments that can't easily be replicated
- Releases need stakeholder approval or coordination
- Compliance requires structured release documentation
- Larger teams benefit from clear branch isolation
- Business prefers predictable, planned release schedules
- You're transitioning from traditional release processes
Neither approach is inherently superior. Both can achieve continuous deployment if implemented well. The key is matching the approach to your context and executing it with discipline.
Making It Work: Practices
Regardless of which strategy you choose, a few practices are essential for successful continuous deployment:
Automated Testing as a Foundation
Quality gates must be automated and comprehensive. Unit tests, integration tests and UI tests should run automatically on every commit. These tests become your confidence in deployment – they must be reliable and fast.
Synchronous Code Reviews
Code reviews can't be allowed to become bottlenecks. Establishing the expectation that pull requests receive attention within 15 minutes keeps code flowing.
Communication and Collaboration
Continuous deployment requires continuous communication. Development teams and testers must collaborate closely, using tools like Slack, Teams or Azure DevOps to stay coordinated. Early feedback loops with product owners and clients help ensure that frequent releases deliver what stakeholders want.
Monitoring and Observability
When deploying frequently, you must know immediately if something goes wrong. Comprehensive monitoring, alerting and logging become essential. The ability to quickly diagnose and resolve production issues provides the confidence to deploy often.
Next Steps
Whether through trunk-based development's simplicity or Git Flow's structured approach – start small. Each increase in deployment frequency teaches lessons about improvements that can be made to testing, automation, monitoring or process.
Moving from continuous integration to genuine continuous deployment represents a significant evolution in development maturity. It requires technical investment in automation and infrastructure, cultural change in how teams approach quality and risk, and organisational trust in development practices.


