Git And Collaboration Workflows
Trunk-Based Development And Branching Strategies
A branching strategy defines how a team integrates, reviews, releases, and supports code. The useful question is not “Which diagram is best?” It is “How quickly can we combine work safely, and what release constraints must the repository support?”
The primary shared branch may be called main, master, or trunk. This lesson uses main for commands and “trunk” for the general idea.
Trunk-Based Development
Trunk-based development keeps developers close to one shared line of integration. Teams either commit directly to trunk with strong safeguards or use short-lived change branches that merge back quickly.
The important properties are:
- integrate frequently
- keep changes small
- maintain a releasable shared branch
- use fast automated checks
- avoid long-lived development branches
- repair a broken trunk immediately
A pull-request workflow can still be trunk-based when branches are small and short-lived. “Trunk-based” does not necessarily mean every developer pushes directly to main.
Short-Lived Change Branches
A lightweight workflow commonly looks like this:
main -> small branch -> pull request -> checks -> review -> main
Branches should last hours or a small number of days, not become alternate integration branches. Split large work into independently safe increments rather than allowing one branch to diverge for weeks.
Short-lived branches reduce, but do not remove, integration risk. The branch should still be updated according to team policy and tested with the current base before merge.
Feature Flags
A feature flag can separate deploying code from exposing behavior. Incomplete functionality can merge behind a disabled flag while development continues in small increments.
Flags introduce their own risks:
- both enabled and disabled paths may require tests
- configuration must be consistent across environments
- authorization must not depend on a cosmetic client-side flag
- stale flags create dead branches and cognitive load
- database changes must remain compatible during rollout
Create an owner and removal condition when adding a temporary flag. A flag is not a substitute for making each merged change safe.
GitHub Flow And Similar Lightweight Workflows
GitHub Flow uses a descriptive branch, commits, a pull request, review and checks, merge into the default branch, then branch deletion. Similar workflows exist on other hosting platforms.
This fits many PHP web applications that deploy one current version and can roll forward frequently. The platform name matters less than the habits: focused branches, reviewable changes, automated checks, and prompt integration.
Release Branches
A release branch can provide a stable line for a version that must continue receiving fixes while new work proceeds on trunk.
This can be appropriate for:
- reusable packages supporting several maintained versions
- on-premises products with scheduled customer upgrades
- regulated or coordinated releases requiring stabilization
- applications where a production version needs patch releases after trunk moves on
Create release branches late and keep normal development on trunk. Fix a bug on trunk first where possible, verify it, then deliberately transfer the relevant commit to an active release branch. This reduces the risk that a production fix never reaches future releases.
A continuously delivered application may release from trunk or tags and need no release branches at all.
Git Flow
The classic Git Flow model uses long-lived main and develop branches plus feature, release, and hotfix branches. It can support explicitly versioned software and multiple releases, but it adds merge paths and process overhead.
The model's original author later advised continuously delivered web applications to consider simpler workflows and cautioned against treating Git Flow as a universal standard.
Use it only when its release structure solves a real need. Do not add develop, release branches, and hotfix branches to a small continuously deployed application merely because a diagram looks formal.
CI Is Part Of The Strategy
Fast integration depends on trustworthy checks. A useful trunk protection path may require:
- syntax and formatting checks
- unit and integration tests
- static analysis
- database migration checks
- security and dependency checks
- a deployable build
Slow or unreliable CI encourages larger batches and bypasses. Improve the feedback path rather than compensating with longer-lived branches.
Choose Based On Constraints
Ask:
- Is there one deployed version or several supported versions?
- How often can the team deploy?
- Can incomplete code remain safe behind a flag or compatible slice?
- How long do reviews and checks take?
- Does the team need stabilization periods?
- Can production fixes be rolled forward quickly?
- Which compliance or approval boundaries are real?
The strategy should be written down. Developers should not discover during an incident whether a fix belongs on main, a hotfix branch, or three release branches.
Warning Signs
Review the workflow when:
- branches regularly live for weeks
- merge conflicts consume significant delivery time
developdiffers from production in unknown ways- release branches receive fixes that never reach trunk
- feature flags have no removal owner
- pull requests are too large to review confidently
- CI is routinely ignored or rerun until it passes
These are feedback problems, not merely Git-command problems.
What To Remember
Trunk-based development minimizes the time work remains unintegrated. Short-lived branches and pull requests can support it, feature flags can separate deployment from release, and release branches can support maintained versions. Git Flow is one contextual model, not a default requirement.
Before moving on, make sure you can explain why a two-day branch and a two-month branch create different integration risk, when a release branch earns its cost, and why CI quality determines whether frequent integration is safe.
Branching Strategy Is Release Strategy
A branching strategy is a way of controlling when work becomes shared, reviewed, tested, released, and supported. It is not mainly about naming. The right strategy depends on deployment frequency, review culture, release risk, regulatory needs, and how often multiple developers touch the same areas.
Trunk-based development keeps integration close to the main branch. Developers use short-lived branches, small pull requests, and feature flags or compatible changes when work cannot be released immediately. The advantage is frequent integration: conflicts and broken assumptions appear quickly. The cost is discipline. Large unfinished work must be sliced safely, and the main branch must stay releasable.
Long-lived feature branches isolate unfinished work but accumulate drift. They can be useful for experiments or large migrations when the team has a deliberate integration plan, but they should not become private alternate realities. The longer a branch lives, the more often it should be rebased or merged from the base, tested, and reviewed in smaller parts.
Release branches serve a different purpose. They stabilize a version while active development continues elsewhere. A release branch needs clear ownership: which fixes may enter it, how they are tested, how hotfixes return to main, and when the branch is retired. Without that policy, fixes diverge and teams rediscover the same bug in multiple lines of history.
Feature Flags And Compatible Changes
Fast branching strategies often depend on feature flags and backward-compatible database changes. A hidden feature can merge before it is active, letting integration happen early while product exposure waits. A flag is not a substitute for design: it needs a default, owner, cleanup date, and behavior when configuration is unavailable.
Database changes should be staged. Add nullable columns or new tables before code requires them, deploy code that writes both old and new shapes if needed, backfill, then remove old paths later. Branching strategy and deployment strategy meet at this point. A branch can merge cleanly and still fail production if the database transition assumes old and new code never overlap.
Choosing A Strategy For A PHP Team
A small PHP application with frequent deployments often benefits from short-lived branches and required checks. A team maintaining a supported product version may need release branches. A consultancy handling client approval may use integration branches for staged review. The point is to choose intentionally and write down how work moves.
Questions to answer include:
- Can
maindeploy at any time? - Are unfinished features hidden or kept out of
main? - Who may push directly to protected branches?
- How are urgent production fixes created and merged back?
- How long can a branch live before review becomes risky?
- Which checks must pass before merge?
- Which merge method keeps history useful for this team?
Integration And Conflict Costs
Every strategy moves cost somewhere. Trunk-based development pays the cost in smaller design slices, more flags, and stronger checks. Long-lived branches pay the cost later as conflicts, stale assumptions, and large reviews. Release branches pay the cost as backports and support policy.
Measure the strategy by outcomes: time from commit to reviewed merge, number of conflicts, failed deployments caused by stale branches, amount of unreleased work, and time to ship a hotfix. If those metrics get worse, the branching policy may need adjustment.
Review And Automation
Branch protection should encode the policy. Required pull requests, status checks, signed commits, merge queues, and restricted pushes are useful when they match the workflow. They become frustrating when they enforce a rule nobody understands.
CI should test the branch as it will merge. If many branches race toward main, a merge queue or required up-to-date branch can prevent a green branch from breaking after another branch lands first. For PHP projects, checks should include dependency installation, static analysis, tests, migrations where safe, and build output when applicable.
Hotfixes
A hotfix should start from the deployed line, not from whatever branch happens to contain unrelated new work. After release, merge or cherry-pick the fix back to main and any supported branches. Record the path so the same defect does not reappear in the next release.
If hotfixes are frequent, ask whether the main branch is too unstable, tests are missing, or release branches are living too long. Branching policy can expose product and quality problems; it cannot solve them alone.
After this lesson, you should be able to compare trunk-based, feature-branch, release-branch, and hotfix workflows; connect branch policy to deployment and database compatibility; use automation to enforce shared rules; and choose a strategy based on integration risk rather than fashion.
Practice
Task: Choose Two Branching Strategies
Recommend a strategy for each team.
Team A
A PHP SaaS application deploys several times per day. It supports one production version, has reliable automated tests, and can release incomplete interface work behind controlled feature flags.
Team B
A reusable PHP package supports three maintained major versions. Customers upgrade on different schedules, and security fixes sometimes need patch releases for all three versions.
For each team, specify:
- the shared development branch model
- expected lifetime of change branches
- whether release branches are needed
- how production or security fixes move between lines
- the required CI behavior
- one workflow risk to monitor
Explain why applying full Git Flow to both teams would ignore important differences.
Show solution
Team A
Use trunk-based development with small pull-request branches that normally merge within hours or a few days. Keep main releasable, run required checks before merge, and use owned, temporary feature flags when a safe incremental slice cannot yet be exposed.
Release branches are unnecessary because only one production line is supported. Fix production defects on main, verify them, and deploy forward. Monitor branch age, pull-request size, stale flags, and flaky CI.
Team B
Use main for future development and explicit release branches for each maintained major line. Keep ordinary change branches short-lived against their intended target. Develop a security fix on the newest applicable line, test it, then deliberately backport or cherry-pick the reviewed fix to each affected release branch.
Each maintained branch needs its own CI run against its supported PHP and dependency versions. Monitor fixes that reach a release branch but are missing from main, and retire branches when support ends.
Full Git Flow adds little value to Team A's continuous delivery path. Team B needs release lines, but it still does not automatically need every Git Flow branch category; the strategy should include only the branches required by its support policy.