Git branching strategies

Git branching strategies are structured approaches to managing branches in version control systems. They define how teams create, merge, and maintain branches throughout the software development lifecycle. A well-defined branching strategy helps teams collaborate effectively, maintain code quality, and streamline the release process.

Why Git branching strategies are important

Implementing a Git branching strategy provides several key benefits:

  • Improved collaboration: Clear guidelines help team members understand how to contribute without conflicts
  • Reduced merge conflicts: Structured branching patterns minimise overlapping changes
  • Simplified rollbacks: Isolated changes make it easier to revert problematic updates
  • Clear development workflow: Team members know exactly where to commit their changes

The right branching strategy depends on your team size, release frequency, and deployment practices. Below are four popular approaches, each with their own strengths and use cases.

Trunk-based development

Description

Trunk-based development is a branching strategy where developers merge small, frequent updates to a trunk (main) branch rather than working on long-lived feature branches. Developers integrate their changes into a shared trunk, potentially multiple times a day. This shared trunk should always be in a deployable state.

The goal of this strategy is to limit long-lived branches and avoid merge conflicts as all developers work on the same branch. This strategy is often combined with feature flags which can help decouple deployment from release so that changes which are not ready can be wrapped in a feature flag and turned off until they’re ready.

How it’s implemented

Trunk-based development uses:

  • trunk (main): The single source of truth, always in a releasable state
  • short-lived feature branches (optional): Very short-lived branches (typically less than a day) for work in progress

The typical workflow:

  1. Pull the latest changes from trunk (typically main)
  2. Create a very short-lived branch or commit directly to trunk (for small changes)
  3. Make small, incremental commits
  4. Run automated tests locally
  5. Push changes directly to trunk (if trusted), or create a pull request from your feature branch into trunk
  6. Merge to trunk after automated checks pass
  7. Use feature flags to hide incomplete features (optional)
  8. Deploy trunk frequently (multiple times per day)

To implement this strategy, there should be a suite of fast automated tests that run after each commit to make sure the system is working. This implementation of CI helps to eliminate long integration and stabilisation phases by integrating small batches at a time.

Benefits and limitations

Benefits Limitations
Encourages small, frequent commits. A key principle in Agile development Requires robust automated testing
Reduces merge conflicts significantly Demands high discipline from developers
Faster feedback and integration Incomplete features need feature flags
Simplifies the development workflow Can be challenging for large distributed teams
A true enabler for CI/CD Requires mature CI/CD infrastructure

Example flow diagram

gitGraph
    commit
    commit
    branch short-lived-branch-1
    checkout short-lived-branch-1
    commit
    commit
    checkout main
    merge short-lived-branch-1
    commit
    branch short-lived-branch-2
    checkout short-lived-branch-2
    commit
    checkout main
    merge short-lived-branch-2
    commit

GitHub-flow

Description

GitHub-flow is a simplified branching strategy developed by GitHub. It’s designed for teams that deploy frequently and practice continuous delivery.

It includes a singular main branch where all release code lives. Temporary feature branches are created from the main branch (e.g. feature/update-dockerfile) and this is where new development takes place. When changes are ready for review, a pull request (PR) is opened to review and discuss the code. As part of this PR, automated tests / checks can be run and the PR decorated with the results. This feature branch can then be deployed directly to production and merged into the main branch (which the team at GitHub do) or merged into main and then main is deployed to production.

Pull requests are a key feature of this strategy and allow developers to add comments and approve or request changes. Whether the PR is approved or not, the record will still exist for future reference. More information on PRs can be found at About pull requests. The idea behind this strategy is that the main branch is in a constantly deployable state and therefore can support CI / CD processes.

How it’s implemented

GitHub-flow uses:

  • main: The single long-lived branch, always deployable
  • feature branches: Short-lived branches for all changes (features, fixes, experiments)

The typical workflow:

  1. Create a branch from main with a descriptive name
  2. Make commits to the branch
  3. Open a pull request to start discussion
  4. Continue making commits based on feedback
  5. Deploy the feature branch to a pre-production environment for testing (optional)
  6. Once ready, merge the pull request into main
  7. Deploy main to production
  8. Delete the feature branch

Benefits and limitations

Benefits Limitations
Simple and easy to understand No separate release preparation phase
Encourages continuous deployment Requires excellent automated testing
Fast feedback through pull requests Main branch must always be deployable
Minimal overhead and branch management No structured way to maintain multiple versions
Works well with CI/CD pipelines Less suitable for scheduled releases

Flow diagram

gitGraph
    commit
    branch feature/a
    checkout main
    commit
    branch feature/b
    commit
    checkout feature/a
    commit
    checkout main
    merge feature/a tag: "PR #1 merged"
    commit
    checkout feature/b
    commit
    checkout main
    merge feature/b tag: "PR #2 merged"
    commit

Git-flow

Description

Git-flow is complex / robust branching strategy which relies on long-lived branches for simultaneously developing new features while supporting current releases. This is considered to be slightly complicated and advanced for much of today’s projects. There are two primary branches, main and develop. The main branch will always reflect the current production-ready state of the software while the develop branch reflects the latest development for the next release. There are also supporting branches such as feature branches which work like they do in GitHub-flow, and release branches which helps prepare the work on develop that will be included in the next release version.

This strategy is well-suited for projects with scheduled release cycles and the need to maintain multiple versions in production.

How it’s implemented

Git-flow uses the following branch types:

  • main (or master): Contains production-ready code. Every commit represents a release.
  • develop: Integration branch for features. Contains the latest delivered development changes.
  • feature branches: Created from develop for new features. Merged back into develop when complete.
  • release branches: Created from develop when preparing a new release. Allows for bug fixes and metadata updates. Merged into both main and develop.
  • hotfix branches: Created from main for urgent production fixes. Merged into both main and develop.

The typical workflow:

  1. Create a feature branch from develop
  2. Develop and test the feature. Testing can happen as part of a pull request targeting develop
  3. Merge feature branch back into develop
  4. Create a release branch from develop when ready
  5. Test and fix bugs in the release branch. Future features can continue to be merged into the develop branch
  6. Merge release branch into main and tag the release
  7. Merge release branch back into develop
  8. For urgent fixes, create hotfix branch from main, fix, and merge into both main and develop

Benefits and limitations

Benefits Limitations
Clear separation between development and production code Complex workflow with many branch types
Supports parallel development of multiple features Steep learning curve for new team members
Well-suited for scheduled releases Overhead of maintaining multiple long-lived branches
Easy to maintain multiple production versions Can lead to delayed integration of features
Structured approach for hotfixes May be overkill for simple projects or continuous deployment

Flow diagram

gitGraph
    commit
    branch develop
    checkout develop
    commit
    
    branch feature/a
    checkout feature/a
    commit
    commit
    
    checkout develop
    merge feature/a
    commit
    
    branch release/1.0
    checkout release/1.0
    commit
    commit
    
    
    checkout main
    merge release/1.0 tag: "v1.0"
    
    checkout develop
    merge release/1.0
    
    checkout main
    branch hotfix
    checkout hotfix
    commit

    checkout main
    merge hotfix
    checkout develop
    merge hotfix

GitLab-flow

Description

GitLab-flow is a branching strategy that combines elements of GitHub-flow with additional branches for different environments. It provides a middle ground between the simplicity of GitHub-flow and the structure of Git-flow, making it suitable for teams that need environment-specific branches but want to avoid the complexity of Git-flow.

How it’s implemented

GitLab-flow consists of a main branch where all code that is going to be deployed into production exists, and various pre-production branches. It can be implemented in two ways:

Environment-based approach:

  • main: Contains production-ready code
  • pre-production: Staging/testing environment
  • production: Production environment branch (receives merges from main)

Release-based approach:

  • main: Development branch
  • release branches: Stable release branches (e.g., 2-3-stable, 2-4-stable)

These approaches are discussed in more detail at Introduction to GitLab-flow.

The typical workflow:

  1. Create a feature branch from main
  2. Develop and test the feature
  3. Create a merge request to main
  4. After review and CI passes, merge to main
  5. Changes automatically flow to pre-production for testing
  6. Once validated, changes are merged/deployed to production
  7. Hotfixes can be applied to release branches and cherry-picked to main

Benefits and limitations

Benefits Limitations
Clear path from development to production More complex than GitHub-flow
Supports multiple environments naturally Requires discipline to maintain environment branches
Balances simplicity with structure Can lead to divergence between environment branches
Works well with continuous delivery May require additional tooling for automation
Easier to understand than Git-flow Not ideal for very frequent deployments

Flow diagram

    gitGraph
        commit
        branch feature/a
        checkout main
        commit
        branch feature/b
        commit
        checkout feature/a
        commit
        checkout main
        merge feature/a tag: "feature/a merged into main"
        commit
        checkout feature/b
        commit
        checkout main
        merge feature/b tag: "feature/b merged into main"
        commit
        branch pre-production
        checkout pre-production
        commit tag: "main merged into pre-production"
        branch production
        commit
        checkout production
        merge pre-production tag: "pre-production merged into production"

Choosing the right strategy

When selecting a branching strategy for your project, consider:

  • Team size and distribution: Larger, distributed teams may benefit from more structure
  • Release frequency: Frequent releases favor simpler strategies like GitHub-flow or trunk-based development
  • Deployment process: Manual deployments may require more structured approaches like Git-flow
  • Team experience: Less experienced teams may need more explicit guidelines
  • Project complexity: Complex projects with multiple versions may need Git-flow or GitLab-flow
  • Testing maturity: Simpler strategies require robust automated testing

Remember, these strategies are guidelines, not strict rules. Many teams adapt and combine elements from different strategies to suit their specific needs and workflows. A good starting point is to choose one of the industry standards above and then modify as necessary.

Common anti-patterns

When devising your Git branching strategy, be aware of the following anti-patterns and avoid them.

Long-lived feature branches

The longer a feature branch exists, the more likely it is to:

  • Contain more code and therefore more conflict opportunities
  • Become out of sync with main, leading to merge conflicts
  • Produce larger, harder-to-review PRs

Feature branches should be short-lived (ideally only a few days). They should be deleted once merged into main. This is in keeping with Agile principles of short, frequent commits.

Managing too many release branches

Every release branch is effectively a codebase you have to maintain. Maintaining numerous long-lived release branches (e.g., supporting 10+ versions simultaneously) creates significant overhead and complexity. Each release branch requires:

  • Backporting bug fixes and security patches to multiple branches
  • Separate CI/CD pipelines and testing for each version
  • Increased cognitive load when deciding where to apply fixes
  • Higher risk of inconsistencies between versions
  • More complex merge conflicts when backporting changes

To avoid this, keep the number of release branches as low as possible.

Using a complicated branching strategy

A branching strategy should be as simple as possible while meeting your team’s needs. Avoid creating unnecessary branches or rules that add overhead without value. If team members regularly ask “which branch should I use?”, your strategy may be too complex.

Further reading


Page last modified: 14 Nov 2025.