Git Workflows : Git Flow, GitHub Flow, and Trunk-Based Development

Git provides branches, commits, merges, tags, remotes, and history-rewriting tools. It does not decide how a team should combine them. That decision belongs to the project’s workflow.

A Git workflow defines how work moves from an idea to production. It answers questions such as: Where does a developer create a branch? How long may that branch remain open? Which tests must pass? Who reviews the change? How is it merged? Where are releases prepared? How are urgent production fixes delivered? Which branches are protected?

The correct workflow is not the one with the most branches or the most famous diagram. It is the simplest model that supports the product’s delivery cadence, release obligations, team size, testing maturity, compliance requirements, and maintenance responsibilities.

This guide explains the major workflow families, including feature branches, GitHub Flow, Git Flow, GitLab-style branching strategies, trunk-based development, and the forking workflow. It also shows how merge methods, CI/CD, feature flags, release branches, and branch protections affect the real result.

What You Will Learn

  • What a Git workflow controls and what Git itself does not control.

  • The difference between a branching strategy and a complete delivery workflow.

  • How the Centralized and Feature Branch workflows operate.

  • How GitHub Flow supports lightweight, pull-request-based collaboration.

  • How Git Flow organizes development, releases, and hotfixes.

  • Why Git Flow is not automatically suitable for continuously delivered web applications.

  • How trunk-based development keeps integration frequent and branches short-lived.

  • How release branches can exist without becoming long-running development branches.

  • How the Forking Workflow supports external contributors.

  • How merge commits, squash merges, and rebasing change history.

  • How branch protection, automated tests, code review, and deployment checks enforce a workflow.

  • How to select and document a workflow for a real project.

What Is a Git Workflow?

A Git workflow is a repeatable agreement for creating, reviewing, integrating, releasing, and maintaining changes in a Git repository.

It may define:

  • The long-lived branches, if any.

  • Where new work starts.

  • How feature and bug-fix branches are named.

  • Whether developers push directly to the main branch.

  • When pull requests or merge requests are required.

  • Which automated checks must pass.

  • How approvals are collected.

  • Which merge method is permitted.

  • Where releases are created.

  • How version tags are applied.

  • How hotfixes and backports are handled.

  • When completed branches are deleted.

A workflow is therefore broader than a branch diagram. A diagram may show main, develop, features, and releases, but it does not tell you whether tests are mandatory, whether reviews are asynchronous, how database migrations are deployed, or how unfinished features are hidden.

Git Workflow vs GitHub Actions Workflow

The word workflow is used in two related but different ways.

  • Git workflow: The human and technical process used to organize branches, commits, reviews, integration, and releases.

  • GitHub Actions workflow: An automated process defined in a YAML file and triggered by repository events.

A Git workflow may require an automated GitHub Actions, GitLab CI/CD, Jenkins, or another pipeline. The pipeline enforces part of the broader development process, but it is not the entire branching strategy.

There Is No Universal Best Workflow

A small web team releasing several times per day has different needs from a desktop application supporting three maintained versions. An open-source library has different permission requirements from a private company repository. A regulated product may require formal approvals that are unnecessary for a personal project.

The workflow should reflect questions such as:

  • How often is the product released?

  • Can production receive changes continuously?

  • Are several released versions maintained simultaneously?

  • How reliable and fast is the test suite?

  • Can unfinished functionality be hidden with feature flags?

  • How many developers contribute?

  • Are contributors trusted with write access?

  • Does the organization require separation of duties?

  • Can a failed deployment be fixed forward quickly?

  • Must releases pass certification or a stabilization period?

Complexity should solve an actual constraint. Every additional permanent branch creates synchronization, policy, automation, and maintenance work.

Core Building Blocks Shared by Most Workflows

Although workflow names differ, most modern Git processes use the same building blocks.

A Stable Default Branch

The default branch is commonly named main. Teams normally expect it to be protected and in a known state, such as deployable, releasable, or at least integrated and tested.

Short, Focused Commits

Commits should represent understandable logical changes. Focused commits improve review, rollback, debugging, cherry-picking, and historical analysis.

Branches for Isolated Work

A branch provides a separate line of development. The important workflow question is not whether branches exist, but how long they live and where they merge.

Code Review

Pull requests and merge requests provide a place to discuss changes, inspect diffs, request improvements, and record approval.

Automated Validation

Tests, linting, security analysis, type checking, builds, migration checks, and deployment previews reduce the risk of integrating broken changes.

Release Identification

Tags, release records, build identifiers, and deployment metadata connect source history to delivered artifacts.

Branch Protection

A hosting platform can prevent direct pushes, require approvals, require successful checks, restrict force pushes, and control who may merge.

Workflow 1: Centralized Workflow

The Centralized Workflow imitates a traditional central repository model while using Git.

All developers clone one shared repository and integrate changes into one primary branch:

A---B---C---D  main

Developers may commit locally, synchronize with the remote, resolve divergence, and push to the shared branch.

Basic Process

  1. Clone the shared repository.

  2. Update the local main branch.

  3. Make and commit changes locally.

  4. Integrate newer remote changes when necessary.

  5. Push to the shared branch.

Advantages

  • Very little branch-management overhead.

  • Easy for a solo developer or very small trusted team.

  • A simple linear mental model.

  • Works for repositories where changes rarely overlap.

Risks

  • Direct pushes can bypass review.

  • A broken commit can immediately affect everyone.

  • Concurrent work creates push conflicts and pressure to integrate quickly.

  • It provides little isolation for unfinished changes.

  • Auditing approvals is difficult without an additional review layer.

When It Fits

This model can work for personal repositories, small documentation projects, temporary prototypes, or a very small team with strong automated validation.

For most team software projects, a feature-branch or trunk-based review workflow provides better control.

Workflow 2: Feature Branch Workflow

The Feature Branch Workflow creates a separate branch for each logical feature, bug fix, refactor, or documentation change.

          C---D  feature/task-search
         /
A---B---E---F    main

The feature branch is reviewed and then integrated into main.

Basic Process

git switch main
git pull --ff-only
git switch -c feature/task-search

# Edit files
git add -p
git commit -m "Add task keyword matching"

git push -u origin feature/task-search

The developer opens a pull request or merge request. After review and successful checks, the branch is merged and deleted.

Advantages

  • Unfinished work remains isolated from the default branch.

  • Each branch gives reviewers a focused unit of discussion.

  • Automated checks can run before integration.

  • Several developers can work independently.

  • The default branch can reject direct pushes.

Risks

  • Long-lived feature branches accumulate divergence.

  • Large pull requests are difficult to review.

  • Late integration exposes conflicts and architectural incompatibilities.

  • Branches may become unofficial permanent environments.

  • Teams may confuse “the branch exists” with “the feature is progressing safely.”

Best Practice

Keep feature branches small and short-lived. A branch should represent one reviewable change, not an entire quarter-long project.

Workflow 3: GitHub Flow

GitHub Flow is a lightweight, branch-based workflow centered on a protected default branch and pull requests.

Its common sequence is:

  1. Create a branch from the default branch.

  2. Make focused commits.

  3. Push the branch.

  4. Open a pull request, possibly as a draft.

  5. Discuss and review the change.

  6. Run automated checks.

  7. Merge after approval.

  8. Deploy the merged result according to the project process.

  9. Delete the completed branch.

The model does not require a permanent develop branch.

             feature/a
            /         \
A---B---C---D-----------E---F  main

Practical GitHub Flow Commands

git switch main
git fetch origin
git merge --ff-only origin/main

git switch -c fix/invoice-rounding

# Make the change
git add -p
git commit -m "Correct invoice tax rounding"

git push -u origin fix/invoice-rounding

After the pull request is merged:

git switch main
git pull --ff-only
git branch -d fix/invoice-rounding

Why It Is Popular

  • Few permanent branches.

  • Easy connection between a change, review, and automated checks.

  • Suitable for frequent deployment.

  • Simple enough for small and medium teams.

  • Draft pull requests support early feedback.

What It Requires

GitHub Flow is simple structurally, but it depends on discipline and automation:

  • The default branch should stay releasable or quickly repairable.

  • Branches should not remain open for long periods.

  • Pull requests should be small enough to review properly.

  • CI must provide fast, trustworthy feedback.

  • Unfinished features may need feature flags.

  • Deployment and rollback processes must be reliable.

When It Fits

GitHub Flow is well suited to web services, APIs, SaaS products, documentation, and applications that can deploy regularly from one primary integration branch.

GitHub Flow Is Not Only for GitHub

The workflow concepts can be implemented on GitLab, Bitbucket, Azure DevOps, or another hosting service. The platform-specific review object may be called a pull request or merge request, but the branching model remains similar.

The name identifies the workflow popularized by GitHub, not a Git command built into the version control system.

Workflow 4: GitLab-Style Simple Branching

GitLab’s current branching guidance emphasizes that many teams can use a simple strategy:

  1. Create a feature branch.

  2. Open a merge request.

  3. Validate and review the change.

  4. Merge directly into main.

This is structurally similar to GitHub Flow.

GitLab also documents more complex strategies for products that maintain historical versions, serve different customer release lines, or have certification and deployment requirements.

Environment Branch Variation

Some teams create branches corresponding to environments:

main
staging
production

Code is promoted by merging through these branches.

This can provide an obvious visual path, but it has risks:

  • The environment branch can drift from what is actually deployed.

  • Hotfixes may flow in the wrong direction.

  • Merge commits can describe deployment mechanics rather than software development.

  • Several branches may contain subtly different code.

Modern delivery systems often prefer immutable build artifacts promoted between environments while the source remains associated with one commit. Use environment branches only when the operational model truly requires them.

Release-Branch Variation

A maintained product may have:

main
release/3.0
release/2.5

New development continues on main, while approved fixes are backported to supported release branches.

This is appropriate when several released versions must remain supported in the wild.

Workflow 5: Git Flow

Git Flow is a structured branching model designed around explicitly versioned releases.

It traditionally uses two long-lived branches:

  • main or historically master: Production-ready release history.

  • develop: Integration branch for the next release.

It also uses temporary supporting branches:

  • feature/*: New work created from develop.

  • release/*: Release stabilization created from develop.

  • hotfix/*: Urgent production repairs created from main.

                feature/a
               /         \
------develop--C-----------D------R------
     /                               \   \
main-A-----------------------------------M---H
                                      hotfix

The exact graph varies, but the important idea is that branch types have defined origins and merge destinations.

Git Flow Is a Convention, Not a Git Feature

Git does not know that a branch named develop is special. Git Flow is a team convention implemented with ordinary branches, merges, and tags.

Optional command-line extensions named git-flow can automate branch creation and finishing steps, but the model does not require them. A team must understand the underlying Git operations rather than depend on wrapper commands blindly.

Git Flow Feature Workflow

Create the long-lived development branch once:

git switch main
git switch -c develop
git push -u origin develop

Create a feature from develop:

git switch develop
git pull --ff-only
git switch -c feature/task-search

# Work and commit
git add -p
git commit -m "Add task keyword matching"

Finish the feature:

git switch develop
git merge --no-ff feature/task-search
git branch -d feature/task-search

The feature does not normally merge directly into main.

Git Flow Release Workflow

When develop contains the features intended for a release:

git switch develop
git switch -c release/2.0.0

The release branch should focus on stabilization tasks such as:

  • Bug fixes.

  • Version updates.

  • Release notes.

  • Packaging adjustments.

  • Final compatibility testing.

Large new features should normally wait for the next release.

When ready:

git switch main
git merge --no-ff release/2.0.0
git tag -a v2.0.0 -m "Release version 2.0.0"

git switch develop
git merge --no-ff release/2.0.0

git branch -d release/2.0.0

The release fixes must return to develop so later releases do not lose them.

Git Flow Hotfix Workflow

An urgent production fix begins from main:

git switch main
git switch -c hotfix/2.0.1

Implement and test the fix:

git add -p
git commit -m "Reject duplicate payment callbacks"

Merge it into production history and tag it:

git switch main
git merge --no-ff hotfix/2.0.1
git tag -a v2.0.1 -m "Release version 2.0.1"

Then merge the fix into develop, or into an active release branch when the project policy requires it:

git switch develop
git merge --no-ff hotfix/2.0.1

git branch -d hotfix/2.0.1

Advantages of Git Flow

  • Explicit separation between production and next-release development.

  • Dedicated release stabilization branches.

  • Clear hotfix path from production.

  • Useful for products with formal versions and scheduled releases.

  • Can support software distributed to customers who upgrade at different times.

  • Provides a shared vocabulary for branch purposes.

Costs of Git Flow

  • Several branches must remain synchronized.

  • Features may wait longer before reaching production.

  • Long-running develop integration can hide release risk.

  • Hotfixes and release fixes must merge into multiple destinations.

  • The history graph can become complex.

  • Continuous delivery becomes harder when production does not come directly from the main integration line.

  • Teams may follow the diagram mechanically even when the product no longer needs it.

When Git Flow Still Fits

Git Flow can fit projects that:

  • Publish explicitly versioned software.

  • Have planned release trains.

  • Need a stabilization period.

  • Support multiple versions used by customers.

  • Cannot deploy every accepted change immediately.

  • Need dedicated hotfix and release coordination.

Examples may include desktop applications, mobile releases constrained by store review, installed enterprise products, firmware, or libraries with maintained release lines.

When Git Flow Is Usually Too Heavy

The model’s original author later clarified that continuously delivered web applications often benefit from a simpler workflow such as GitHub Flow. Git Flow should not be treated as a universal standard.

It may be unnecessary when:

  • The team deploys from main many times per day.

  • Only one production version is active.

  • Changes can be hidden with feature flags.

  • Automated testing and deployment are mature.

  • Fix-forward is the normal operational strategy.

  • A permanent develop branch adds delay without solving a release constraint.

Workflow 6: Trunk-Based Development

Trunk-based development organizes work around one main integration branch, commonly called main or trunk.

Developers either:

  • Commit directly to trunk in a very small, highly disciplined team.

  • Use very short-lived feature branches that merge into trunk quickly.

       a
      / \
A---B---C---D---E---F  main
          \ /
           b

The branches are intentionally brief. The defining characteristic is frequent integration, not the literal absence of branches.

Trunk-Based Development Is Not “Everyone Pushes Anything to Main”

A successful trunk-based workflow requires strong engineering controls:

  • Fast automated tests.

  • Small changes.

  • Continuous integration.

  • Frequent synchronization.

  • Code review that does not create long delays.

  • Feature flags for incomplete user-facing work.

  • Branch by abstraction for large structural changes.

  • Reliable deployment and monitoring.

  • Fast repair when trunk becomes unhealthy.

Direct-to-trunk work without these practices is not mature trunk-based development. It is simply uncontrolled integration.

Short-Lived Branch Version

A common scaled workflow is:

git switch main
git pull --ff-only
git switch -c change/add-search-index

# Complete a small increment
git add -p
git commit -m "Add task search index"

git push -u origin change/add-search-index

A pull request runs checks and receives rapid review. It merges within hours or a small number of days, not weeks.

The next large feature increment begins from the updated trunk as another small change.

Feature Flags in Trunk-Based Development

A feature flag separates code integration from feature activation.

Example:

if (FeatureFlags::enabled('task_search_v2')) {
    return $newSearchService->search($query);
}

return $legacySearchService->search($query);

The incomplete implementation can enter main while remaining disabled for normal users.

Flags can support:

  • Incremental delivery.

  • Internal testing.

  • Percentage-based rollout.

  • Customer-specific activation.

  • Fast operational deactivation.

Flags also create maintenance work. Old flags should be removed after rollout decisions are complete.

Branch by Abstraction

Large architectural work may not fit one tiny commit. Branch by abstraction allows old and new implementations to coexist behind a stable interface.

A simplified process is:

  1. Introduce an abstraction around the current behavior.

  2. Move existing behavior behind the abstraction.

  3. Add the new implementation incrementally.

  4. Select behavior through configuration or a feature flag.

  5. Migrate callers and data safely.

  6. Remove the old implementation and temporary abstraction when appropriate.

This keeps integration frequent without requiring a long-lived rewrite branch.

Releasing in Trunk-Based Development

Two common approaches are:

Release Directly from Trunk

Every accepted trunk commit should be a potential release candidate. Deployment automation selects or continuously deploys a tested commit.

Cut a Release Branch Just in Time

A release branch is created near release time:

git switch main
git switch -c release/3.2

New development continues on main. The release branch accepts only release-critical fixes, often developed on trunk first and then backported.

This is different from using a long-lived release-development branch where all feature work accumulates for months.

Advantages of Trunk-Based Development

  • Integration happens continuously rather than near the end.

  • Conflicts are usually smaller because divergence is limited.

  • There is one primary source of current development truth.

  • It supports continuous delivery and rapid feedback.

  • Large integration events are avoided.

  • Teams discover incompatible changes earlier.

Risks and Requirements

  • Weak automated tests can allow frequent breakage.

  • Slow reviews turn short-lived branches into long-lived branches.

  • Large changes require feature flags or abstraction techniques.

  • Developers must divide work into small increments.

  • A broken trunk must receive immediate attention.

  • Poor flag management can produce hidden complexity.

Workflow 7: Forking Workflow

The Forking Workflow is common in open-source projects and repositories where contributors should not receive direct write access.

Each contributor has:

  • A local clone.

  • A personal server-side fork.

  • A remote connection to the official repository.

A common remote convention is:

  • origin: The contributor’s fork.

  • upstream: The official repository.

Initial Setup

git clone git@github.com:contributor/project.git
cd project

git remote add upstream git@github.com:organization/project.git
git remote -v

Update from the Official Repository

git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

Create and Publish a Contribution

git switch -c fix/date-parser

# Make and commit changes
git add -p
git commit -m "Reject invalid calendar dates"

git push -u origin fix/date-parser

The contributor opens a pull request from the fork branch into the official repository.

Advantages

  • External contributors do not need write access to the official repository.

  • Maintainers control integration.

  • Contributors can publish and test their own branches.

  • It scales to open communities.

Costs

  • Contributors must manage two remotes.

  • Fork branches can become outdated.

  • CI secrets and permissions may be restricted for untrusted fork builds.

  • Maintainers need clear contribution and review policies.

Merge Methods Are Part of the Workflow

A pull request can be integrated in several ways. The selected method changes repository history.

Merge Commit

git switch main
git merge --no-ff feature/task-search

Characteristics:

  • Preserves the feature branch’s individual commits.

  • Creates an explicit integration commit.

  • Maintains the branch topology.

  • Can create a visually complex history when branches are numerous.

Squash Merge

A hosting platform or local workflow combines the feature diff into one new commit on the target branch.

A---B---S  main
     \
      C---D---E  feature

Characteristics:

  • Produces one commit per pull request.

  • Allows messy branch commits without preserving them on main.

  • Removes the original parent relationship between target history and feature commits.

  • Can make partial reversion simpler at the pull-request level.

  • Loses granular feature-branch history from the main line.

Rebase and Merge

The feature commits are replayed onto the target branch and added without a merge commit:

A---B---C'---D'---E'  main

Characteristics:

  • Creates a linear history.

  • Preserves individual logical commits when they are clean.

  • Creates replacement commit identifiers.

  • Requires care when the original branch history has already been shared.

  • Does not create an explicit merge commit.

How to Choose a Merge Method

MethodBest WhenMain Trade-off
Merge commitBranch topology and integration events matterMore complex graph
Squash mergeOne reviewed change should become one mainline commitFeature commit detail is removed from mainline history
Rebase and mergeFeature commits are clean and linear history is desiredCommits are rewritten and no merge boundary remains

The team should choose one or a small set of allowed methods and document when each is used. Inconsistent merging makes history harder to interpret.

Pull Requests Are a Collaboration Layer, Not a Git Object

Git itself understands commits, branches, tags, merges, and remotes. A pull request or merge request is provided by a hosting platform.

It adds:

  • Discussion.

  • Inline comments.

  • Review status.

  • Automated-check summaries.

  • Linked issues.

  • Approval records.

  • Merge controls.

  • Deployment previews.

The final Git history may contain a merge commit, a squash commit, or rebased commits depending on the selected integration method.

Draft Pull Requests and Early Review

A draft pull request can expose work before it is ready to merge.

This is useful when:

  • The developer wants architectural feedback early.

  • The change affects several teams.

  • CI should run before implementation is complete.

  • A visible discussion is preferable to private work.

  • The branch must remain short-lived but requires collaboration.

A draft should not become an excuse for an indefinitely open branch. Split large work into independently integrable increments.

Branch Protection and Rules

A written workflow becomes reliable when repository settings enforce its critical rules.

Common protections include:

  • Block direct pushes to main.

  • Require a pull request or merge request.

  • Require one or more approvals.

  • Dismiss approvals after significant new commits.

  • Require conversations to be resolved.

  • Require selected status checks.

  • Require the branch to be current with the target.

  • Require signed commits or tags when appropriate.

  • Restrict who can merge or create releases.

  • Prevent branch deletion or force pushes.

Do not enable every available rule automatically. Each required check becomes part of the delivery path and must remain reliable.

CI/CD as the Workflow’s Feedback System

A workflow without fast validation often produces long waiting periods and large risky merges.

A pull-request pipeline may run:

  1. Dependency installation.

  2. Formatting and lint checks.

  3. Static analysis.

  4. Unit tests.

  5. Integration tests.

  6. Security and secret scanning.

  7. Database migration validation.

  8. Application build.

  9. Container build.

  10. Preview environment deployment.

A post-merge pipeline may:

  • Build an immutable artifact.

  • Deploy to staging.

  • Run smoke tests.

  • Promote the same artifact to production.

  • Create a release record.

  • Record the commit and tag deployed.

Keep the Main Branch Green

A green main branch means the latest integrated state passes the required validation.

When it becomes red:

  • Stop adding unrelated changes when necessary.

  • Identify the responsible integration quickly.

  • Revert or fix forward according to team policy.

  • Restore the branch before continuing normal delivery.

  • Improve the missing test or validation that allowed the failure.

A broken main branch that remains broken for days destroys trust in the workflow.

Release Branches: Long-Lived vs Just-in-Time

The name release/* can describe two very different strategies.

Long-Lived Supported Release Branch

main
release/3.x
release/2.x

These branches exist because multiple released versions remain supported.

Temporary Stabilization Branch

release/4.0.0

This branch exists only while one release is finalized, then is merged or retired.

Just-in-Time Branch from Trunk

The branch is cut near release time, receives only release-critical changes, and is deleted after support obligations end.

A workflow document should specify which meaning applies.

Hotfixes and Backports

A hotfix repairs active production. A backport applies a fix to an older supported release line.

A safe principle is to develop the fix in the oldest relevant code line when necessary, then propagate it toward newer lines, or develop it on trunk and cherry-pick it backward when the project’s policy supports that approach.

Example backport:

# The fix exists on main as abc1234
git switch release/2.5
git cherry-pick -x abc1234

The -x option records the original commit identifier in the new commit message when the cherry-pick completes without conflicts, helping trace the backport.

After backporting:

  • Run the tests for the older release.

  • Verify compatibility with older dependencies and schemas.

  • Create the appropriate patch release tag.

  • Confirm the fix is also present in newer maintained lines.

Feature Flags vs Feature Branches

A feature branch isolates source history. A feature flag controls runtime behavior.

Feature BranchFeature Flag
Separates commits before integrationSeparates deployment from activation
Can accumulate merge divergenceCan accumulate runtime complexity
Useful for review and isolationUseful for incremental rollout and hidden work
Removed after mergingShould be removed after rollout decisions

Mature teams often use both: a short-lived branch for review and a flag to keep the incomplete capability disabled after integration.

Manual Run: Lightweight Pull-Request Workflow

1. Prepare Main

git switch main
git fetch origin
git merge --ff-only origin/main
git status

2. Create a Focused Branch

git switch -c feature/task-search

3. Create Logical Commits

git add src/SearchService.php
git commit -m "Add task keyword matching"

git add tests/SearchServiceTest.php
git commit -m "Test task keyword matching"

4. Review the Branch

git log --oneline main..HEAD
git diff --stat main...HEAD
git diff main...HEAD

5. Publish

git push -u origin feature/task-search

6. Pull Request Checks

  • Automated tests pass.

  • The diff contains one logical feature.

  • No secrets or generated files are present.

  • Review comments are resolved.

  • The branch is updated when required by policy.

7. Merge and Clean Up

git switch main
git pull --ff-only
git branch -d feature/task-search

Manual Run: Git Flow Release

Initial Long-Lived Branches

A---B---C  main
         \
          D---E---F  develop

Create the Release Branch

git switch develop
git switch -c release/2.0.0

Stabilize

git add CHANGELOG.md
git commit -m "Prepare release notes for 2.0.0"

git add src/Version.php
git commit -m "Set application version to 2.0.0"

Merge to Main and Tag

git switch main
git merge --no-ff release/2.0.0
git tag -a v2.0.0 -m "Release version 2.0.0"

Return Release Fixes to Develop

git switch develop
git merge --no-ff release/2.0.0
git branch -d release/2.0.0

Verify

git log --oneline --graph --decorate --all
git show v2.0.0

Manual Run: Trunk-Based Increment Behind a Flag

1. Create a Short-Lived Branch

git switch main
git pull --ff-only
git switch -c change/search-routing

2. Add a Disabled Flag Path

if (FeatureFlags::enabled('new_task_search')) {
    return $newSearch->execute($query);
}

return $oldSearch->execute($query);

3. Commit a Small Safe Increment

git add -p
git commit -m "Route task search through feature flag"

4. Validate and Merge Quickly

git diff main...HEAD
git push -u origin change/search-routing

After review and CI, merge the branch. The new path remains disabled.

5. Continue Through New Small Branches

  • Add the new search implementation.

  • Add comparison metrics.

  • Enable it for internal users.

  • Roll out gradually.

  • Remove the old implementation.

  • Remove the flag.

The large feature reaches production through multiple safe, integrated increments rather than one long-lived branch.

Workflow Comparison

WorkflowLong-Lived BranchesIntegration FrequencyRelease StyleTypical Fit
CentralizedUsually oneDirect and frequentProject-specificSolo or very small trusted teams
Feature BranchUsually mainPer completed branchFlexibleGeneral team collaboration
GitHub FlowMainFrequent pull requestsFrequent deployment from mainWeb, SaaS, APIs, documentation
Git FlowMain and developFeature and release stagesVersioned scheduled releasesProducts with formal release cycles
Trunk-BasedMain/trunkVery frequentFrom trunk or just-in-time release branchContinuous integration and delivery
ForkingDepends on upstream projectThrough external pull requestsMaintainer-controlledOpen source and restricted contributors

How to Choose a Workflow

Choose a Lightweight Main-and-Feature-Branch Model When:

  • The team releases regularly.

  • One current production version exists.

  • Pull requests and CI provide sufficient control.

  • A permanent integration branch would add little value.

Choose Git Flow or a Release-Oriented Model When:

  • Releases are explicitly versioned and scheduled.

  • A formal stabilization branch is necessary.

  • Multiple versions may require maintenance.

  • Hotfixes must follow a defined release process.

  • Deployment cannot occur after every accepted change.

Choose Trunk-Based Development When:

  • Automated validation is fast and reliable.

  • The team can divide work into small increments.

  • Integration and deployment are frequent.

  • Feature flags and branch-by-abstraction techniques are available.

  • The team reacts immediately to a broken trunk.

Choose the Forking Workflow When:

  • Contributors should not receive write access.

  • The project is public or accepts external contributions.

  • Maintainers need control over official repository integration.

  • The hosting platform supports pull requests across forks.

A Practical Decision Matrix

Project ConditionLikely Direction
Deploy several times per dayGitHub Flow or trunk-based development
One small team, strong CI, short reviewsShort-lived branches around main
Monthly packaged releasesRelease branches or Git Flow
Support several customer versionsMaintained release branches
Large open-source contributor baseForking workflow plus maintainer review
Weak or slow automated testsImprove validation before increasing integration speed
Features take months to buildSplit increments, feature flags, and branch by abstraction
Formal approval and audit requirementsProtected branches with mandatory reviews and checks

Workflow Anti-Patterns

Long-Lived Feature Branches

They postpone integration and create large, risky merge events.

A Permanent Develop Branch Without a Release Need

If every accepted change should eventually deploy from main, an additional integration branch may only add synchronization delay.

Environment Branches That Do Not Match Deployments

A branch name is not proof of what is running in an environment. Record deployed commits and artifacts explicitly.

Huge Pull Requests

Review quality declines as size and complexity increase.

Branches Named After People

Names such as adnan-work describe ownership rather than purpose and can collect unrelated changes.

Blindly Rebasing Shared Branches

Rewriting published commits disrupts collaborators and automated references.

Using Cherry-Pick as the Default Integration Method

Cherry-pick copies individual changes but does not represent a branch-level integration relationship. Use it intentionally for backports and selected commits.

Protecting Main with Unreliable Checks

A flaky mandatory test can block every developer and teach the team to distrust automation.

Keeping Dead Branches Forever

Stale branches make repository state harder to understand.

Choosing a Workflow Because a Tool Has a Button for It

The product’s release and maintenance constraints should drive the process, not a hosting-platform feature list.

Workflow Best Practices

  • Use the fewest permanent branches that solve the real problem.

  • Keep branches short-lived whenever possible.

  • Separate unrelated changes.

  • Review the branch diff, not only individual commits.

  • Require fast, relevant automated checks.

  • Keep the default branch healthy.

  • Delete completed temporary branches.

  • Use release tags to identify delivered versions.

  • Document hotfix and backport paths.

  • Define the allowed merge methods.

  • Use feature flags for incomplete integrated functionality.

  • Remove stale feature flags.

  • Record which commit and artifact reached each environment.

  • Reevaluate the workflow when delivery needs change.

Document the Workflow in the Repository

A practical workflow document should answer:

  • What is the default branch?

  • Can anyone push to it directly?

  • Where should feature branches start?

  • How are branches named?

  • How small should pull requests be?

  • Which checks and approvals are required?

  • Which merge methods are allowed?

  • Who may create release tags?

  • How are releases created?

  • How are production hotfixes handled?

  • How are fixes backported?

  • When should branches be deleted?

  • What happens when the main branch is broken?

Store the policy in a visible file such as:

CONTRIBUTING.md
docs/development-workflow.md
docs/release-process.md

The document should describe decisions, not merely list commands.

Example Lightweight Team Policy

Default branch: main

Branch names:
- feature/<short-description>
- fix/<short-description>
- docs/<short-description>

Rules:
1. Direct pushes to main are blocked.
2. Every change uses a pull request.
3. At least one approval is required.
4. Unit tests, static analysis, and build checks must pass.
5. Pull requests should contain one logical change.
6. Squash merge is used for normal feature branches.
7. Release tags are annotated and created by the release pipeline.
8. Completed branches are deleted automatically.
9. A broken main branch receives immediate repair or revert.

Example Release-Oriented Team Policy

Long-lived branches:
- main: released production versions
- develop: next planned release

Supporting branches:
- feature/* from develop
- release/* from develop
- hotfix/* from main

Rules:
1. Feature branches merge into develop.
2. Release branches accept only stabilization changes.
3. Completed releases merge into main and develop.
4. Main release commits receive annotated version tags.
5. Hotfixes merge into main and develop.
6. Supported release branches receive approved backports.
7. No force pushes are allowed on protected branches.

Migrating from Git Flow to a Simpler Workflow

A team that no longer needs formal release branches can simplify gradually.

  1. Identify why develop exists today.

  2. Confirm that main can become the primary integration branch.

  3. Improve CI and deployment automation.

  4. Shorten feature-branch lifetime.

  5. Move release preparation into automation or just-in-time branches.

  6. Merge the required develop history into main.

  7. Update branch protections and pipeline triggers.

  8. Update documentation and developer tooling.

  9. Retire develop only after active work is accounted for.

Do not delete a long-lived branch without identifying unique commits, open pull requests, and pipeline dependencies.

Migrating Toward Trunk-Based Development

Trunk-based development is an engineering capability, not a branch rename.

A realistic migration may involve:

  1. Reduce pull-request size.

  2. Improve test reliability and execution time.

  3. Automate formatting and static checks.

  4. Introduce feature flags.

  5. Teach branch by abstraction.

  6. Set a maximum expected branch lifetime.

  7. Provide rapid review ownership.

  8. Measure how long changes wait before integration.

  9. Strengthen observability and deployment rollback or fix-forward procedures.

  10. Remove unnecessary permanent branches.

Metrics That Reveal Workflow Problems

Useful indicators include:

  • Median branch lifetime.

  • Pull-request waiting time.

  • Review turnaround time.

  • Pull-request size.

  • Merge-conflict frequency.

  • CI duration and failure rate.

  • Time the default branch remains broken.

  • Deployment frequency.

  • Lead time from first commit to production.

  • Change failure and recovery rates.

  • Number and age of stale branches.

  • Number and age of stale feature flags.

Metrics should guide improvement, not become targets that developers manipulate.

Git Workflow Checklist

Before adopting a workflow:

  • The release cadence is understood.

  • The supported-version policy is documented.

  • The default branch’s expected state is defined.

  • Required permanent branches have a real purpose.

  • The review and approval model is clear.

  • The CI pipeline is reliable enough to enforce required checks.

  • The merge method is selected intentionally.

  • The hotfix and backport process is defined.

  • Release tags and artifact provenance are defined.

  • Branch protections match the written policy.

During daily work:

  • Start from the correct updated base.

  • Create one branch per logical change.

  • Keep commits understandable.

  • Push regularly when collaboration or backup is needed.

  • Open review early for risky work.

  • Keep the branch short-lived.

  • Respond to CI and review feedback promptly.

  • Delete the branch after integration.

Frequently Asked Questions

Is Git Flow Built into Git?

No. It is a branching convention implemented with ordinary Git commands. Optional extensions can automate parts of it.

Is GitHub Flow Only for GitHub?

No. Its short-lived branch and review model can be used on other hosting platforms.

Does Trunk-Based Development Ban Branches?

No. Larger teams commonly use very short-lived branches for review and automated validation.

Should Every Project Have a develop Branch?

No. Add it only when it represents a real integration or release stage that the main branch cannot serve.

Which Workflow Is Best for Laravel or Web Applications?

For a web application deployed regularly, a protected main branch with short-lived feature branches, pull requests, CI, and feature flags is often simpler than full Git Flow. The project’s deployment and support constraints still determine the final choice.

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

They can look similar. Both may use one main branch and short-lived branches. Trunk-based development emphasizes very frequent integration, minimal branch lifetime, and techniques such as feature flags. GitHub Flow emphasizes the pull-request collaboration sequence and deployment from the default branch.

When Should I Use Git Flow?

Use it when formal versioned releases, stabilization branches, production hotfix paths, and support for released versions justify the added branch structure.

Should Main Always Be Deployable?

That depends on the workflow, but GitHub Flow and trunk-based models generally work best when main is releasable or can be restored quickly.

Should We Squash Every Pull Request?

Not automatically. Squashing is useful when the pull request should become one logical mainline commit. Preserve individual commits when they carry valuable independent history.

Should Developers Rebase Before Opening a Pull Request?

Only when the team’s history policy requires it and the branch is safe to rewrite. Do not rebase shared work casually.

Are Release Branches Incompatible with Trunk-Based Development?

No. A just-in-time release branch can be cut from trunk when needed. The key difference is that feature development continues through trunk rather than accumulating on long-lived release branches.

How Long Should a Feature Branch Live?

As briefly as practical. A lightweight review workflow may tolerate a few days, while trunk-based teams aim for hours or very short periods. A branch lasting weeks is a signal that the work should be divided.

Can CI Replace Code Review?

No. Automation checks defined properties. Human review evaluates design, intent, maintainability, product behavior, and risks not fully expressed in tests.

Can Code Review Replace CI?

No. Humans are poor substitutes for repeatable automated validation.

How Should an Urgent Production Fix Be Handled?

Create the fix from the production source of truth, validate it, release it, and ensure the correction reaches every newer active development or release line.

Conclusion

A Git workflow is an agreement about how changes become trusted software. Branch names and diagrams are only the visible structure. The real workflow also includes reviews, automated tests, merge methods, branch protection, release identification, deployment, and maintenance.

For many modern teams, a protected main branch with small short-lived branches and pull requests is the best starting point. GitHub Flow expresses that model clearly. Trunk-based development takes frequent integration further and depends on strong automation, small increments, feature flags, and rapid review.

Git Flow remains useful when the product has formal versioned releases, stabilization periods, production hotfixes, and multiple versions in the wild. Its additional branches should solve those real constraints rather than exist because the model is familiar.

The Forking Workflow addresses a different problem: accepting contributions without granting write access to the official repository.

The most important rule is to avoid accidental complexity. Start with the simplest workflow that protects the default branch and supports review. Add release branches, hotfix paths, approval layers, or maintained versions only when the product requires them. Reevaluate the process as delivery capabilities and business needs change.

The next article will focus on Git best practices for clean commits and team collaboration, bringing together branch naming, commit design, review quality, security, repository maintenance, and safe history management.

Official References and Further Reading