Trunk-Based Development for Enterprise CI/CD: Architecture, Implementation, and Security
Prerequisites
- Working knowledge of Git and pull requests
- Basic familiarity with CI/CD pipelines and branch protection
Steps
Trunk-based development keeps developers integrating to a single mainline frequently, reducing merge debt and accelerating delivery. For enterprises, it enables smaller changes, safer releases, stronger policy enforcement, and more reliable CI/CD automation.
Overview
Trunk-based development (TBD) is a source control practice where engineers commit small, frequent changes to a single shared branch, usually main or trunk. Short-lived feature branches may exist for hours, not weeks, and incomplete work is protected with feature flags rather than long-running isolation.
Its core purpose is to reduce integration risk. Instead of accumulating divergent code paths that merge late and fail unpredictably, teams validate continuously through automated builds, tests, security scans, and deployment checks. Enterprises adopt TBD because it improves release cadence, supports platform engineering standards, and creates a cleaner audit trail for regulated delivery pipelines.
Common enterprise drivers include:
- Lower merge conflict volume and faster recovery from failed integrations
- Better CI signal because every change targets the same production path
- Easier enforcement of branch protection, signed commits, and policy gates
- Improved compatibility with continuous delivery and progressive deployment
Architecture
A typical enterprise TBD architecture includes:
- Source control: GitHub Enterprise, GitLab, or Azure DevOps with protected
main - CI orchestration: GitHub Actions, GitLab CI, Jenkins, or Azure Pipelines
- Artifact management: JFrog Artifactory, GitHub Container Registry, or Amazon ECR
- Feature flag service: LaunchDarkly, OpenFeature-compatible platform, or internal toggles
- Security controls: SAST, dependency scanning, secret scanning, signed commits, OIDC workload identity
- Deployment target: Kubernetes, VMs, serverless, or hybrid environments
Data flow is straightforward:
- A developer rebases from
mainand creates a short-lived branch. - Code is committed, signed, pushed, and validated by CI.
- Pull request checks enforce tests, linting, SAST, and approval policy.
- The branch is merged quickly into
main. - A pipeline builds an immutable artifact, signs it, and deploys to staging or production using progressive rollout.
- Feature flags control runtime exposure independently of deployment.
Deployment models commonly used with TBD:
- SaaS SCM + SaaS CI for speed and lower ops overhead
- Self-hosted SCM + runners for data residency and network control
- Hybrid where code remains on-prem and deployments target cloud workloads
Implementation Guide
- Create and protect the trunk branch.
git init
git checkout -b main
git add .
git commit -S -m "chore: initial commit"
git remote add origin git@github.com:enterprise/app.git
git push -u origin main
- Enforce linear history and small PRs.
gh repo edit enterprise/app --default-branch main
gh api -X PUT repos/enterprise/app/branches/main/protection -f required_linear_history=true -f enforce_admins=true -f required_pull_request_reviews.dismiss_stale_reviews=true -F required_status_checks.strict=true -f restrictions='null'
- Add a CI workflow with build, test, and security gates.
name: ci
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
id-token: write
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install -r requirements.txt bandit pytest
- run: pytest -q
- run: bandit -r . -f txt
- Standardize short-lived branch creation.
git checkout main
git pull --rebase origin main
git checkout -b feat/payment-timeout-metric
- Merge quickly and delete the branch after checks pass.
gh pr create --fill --base main
gh pr merge --squash --delete-branch
- Use feature flags for incomplete code paths and deploy continuously from
main.
Code Examples
Example 1: Git policy bootstrap
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global commit.gpgsign true
git config --global init.defaultBranch main
Example 2: Branch protection as code
{
"required_status_checks": {
"strict": true,
"contexts": ["validate"]
},
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 1,
"dismiss_stale_reviews": true
},
"restrictions": null,
"required_linear_history": true,
"allow_force_pushes": false,
"allow_deletions": false
}
Example 3: Feature flag guard in Python
import os
def is_enabled(flag_name: str) -> bool:
return os.getenv(flag_name, "false").lower() == "true"
def handle_checkout(user_id: str) -> str:
if is_enabled("FF_NEW_CHECKOUT"):
return f"new-checkout-flow:{user_id}"
return f"classic-checkout-flow:{user_id}"
Security Hardening
- Require signed commits and protected
mainto prevent unauthorized history changes. - Use OIDC federation from CI to cloud providers instead of long-lived secrets.
- Encrypt artifacts at rest with platform-managed KMS keys and enforce TLS 1.2+ in transit.
- Restrict merge permissions with least privilege and CODEOWNERS for critical paths.
- Enable secret scanning and block commits containing credentials.
- Sign build artifacts and container images with Sigstore Cosign or equivalent.
- Store audit logs centrally in SIEM for branch protection changes, merges, and deployment events.
Comparison
| Capability | Trunk-Based Development | GitFlow | GitHub Flow |
|---|---|---|---|
| Pricing | Process model, no direct license cost | Process model, no direct license cost | Process model, no direct license cost |
| Deployment | Best for continuous delivery from main | Better for scheduled releases and multiple long-lived branches | Good for web apps with frequent deploys |
| Scalability | High for large teams with strong automation | Medium, merge complexity grows with release branches | High for smaller to medium teams |
| Security | Strong when combined with branch protection, signed commits, and policy gates | More control points but larger merge surface | Strong, but can drift if PR discipline is weak |
Troubleshooting
1. Non-fast-forward push rejected
Log sample:
! [rejected] feat/api-cache -> feat/api-cache (non-fast-forward)
error: failed to push some refs to 'git@github.com:enterprise/app.git'
hint: Updates were rejected because the tip of your current branch is behind its remote counterpart.
Fix: Rebase on latest main or remote branch, then push again.
git fetch origin
git rebase origin/main
git push --force-with-lease
2. Required status check failed
Log sample:
ERROR: Process completed with exit code 1.
FAILED tests/test_checkout.py::test_new_flow - AssertionError: expected 200 got 500
bandit: Issue: [B105:hardcoded_password_string] Possible hardcoded password: 'admin123'
Fix: Correct the failing test, remove insecure literals, and rerun CI locally before pushing.
3. Branch protection blocked direct push
Log sample:
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Changes must be made through a pull request.
To github.com:enterprise/app.git
! [remote rejected] main -> main (protected branch hook declined)
Fix: Create a PR, obtain approval, and merge through the platform workflow.
Best Practices
Do
- Keep branches under one day of lifetime when possible.
- Merge small batches, for example 100-300 lines changed instead of multi-week epics.
- Use feature flags for incomplete work and dark launches.
- Make
mainalways releasable with mandatory automated tests. - Track DORA metrics to verify reduced lead time and change failure rate.
Don't
- Do not keep long-lived feature branches that diverge for weeks.
- Do not bypass branch protection for urgent fixes; use an expedited PR path.
- Do not couple deployment and release visibility; deploy safely, release with flags.
- Do not rely on manual regression alone; TBD requires fast automated validation.
A practical enterprise pattern is: short-lived branch, PR with one approval, automated security gates, squash merge to main, signed artifact, progressive deployment, and feature-flagged release. That combination delivers the speed benefits of TBD without sacrificing governance or security.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI