Lesson 110 of 12125 min read

Git Flow: main, develop, feature/*, release/*, hotfix/* Branch Model

Learn Git Flow, the most structured and formal branching strategy, with five distinct branch types each serving a specific, defined purpose.

Author: CodersNexus

Git Flow: main, develop, feature/*, release/*, hotfix/* Branch Model

Git Flow, first popularized by Vincent Driessen in 2010, is the most formally structured of the branching strategies covered in this module — defining five distinct branch types, each with a specific, well-defined purpose and lifecycle. Understanding it in depth provides a strong foundation for evaluating the simpler strategies covered in the following lessons, since many of them were explicitly designed as reactions to Git Flow's complexity.

Learning Objectives

  • Identify Git Flow's five branch types and the specific purpose of each.
  • Explain the relationship and merge direction between main, develop, feature, release, and hotfix branches.
  • Trace a complete feature's lifecycle through the Git Flow model.
  • Trace a hotfix's lifecycle, including how it reaches both main and develop.

Key Terms to Know Before Learning Git Flow

  • main (or master): A long-running branch in Git Flow representing the official release history — every commit here corresponds to a released version.
  • develop: A long-running branch representing the latest integrated development work, serving as the base for new feature branches and the target for completed ones.
  • feature/* branches: Short-lived branches, one per feature, branched from develop and merged back into develop once complete.
  • release/* branches: Short-lived branches created from develop to prepare, stabilize, and finalize a specific release before it merges into both main and develop.
  • hotfix/* branches: Short-lived branches created directly from main to urgently fix a critical production bug, merged into both main and develop upon completion.

How the Git Flow Branching Model Actually Works

Git Flow defines **two long-running branches** and **three types of short-lived, supporting branches**, each with a strictly defined role:

**`main`** (sometimes still called `master` in older documentation) represents the **official release history** — every single commit on this branch corresponds to a version that has actually been released to production. This branch should always be in a genuinely deployable state.

**`develop`** represents the **latest integrated development work** — a continuously updated branch where completed features accumulate before being batched into a formal release. This is the base that new feature work branches from, and the target that completed feature work merges back into.

**`feature/*`** branches (e.g., `feature/user-authentication`) are created **from `develop`**, used for building one specific piece of new functionality, and merged **back into `develop`** once complete — directly following Module 3's short-lived branch principles. Critically, feature branches never interact directly with `main` at all in the standard Git Flow model.

**`release/*`** branches (e.g., `release/2.4.0`) are created **from `develop`** once enough completed features have accumulated to justify preparing a new, formal release. This branch is specifically for **stabilization** — final testing, minor bug fixes, updating version numbers and documentation — deliberately *not* for adding new features (those continue to accumulate on `develop` in parallel, targeting the *next* release instead). Once stabilized and ready, a release branch merges into **both** `main` (marking the actual release, typically tagged per Module 2's tagging lesson) **and back into `develop`** (ensuring any last-minute stabilization fixes made on the release branch aren't lost from ongoing development).

**`hotfix/*`** branches (e.g., `hotfix/payment-crash`) are created directly **from `main`** — not `develop` — specifically to urgently address a critical bug in already-released, production code, exactly the scenario introduced back in Module 3. Once fixed, a hotfix branch merges into **both** `main` (immediately shipping the fix) **and `develop`** (ensuring the fix isn't lost or reintroduced when `develop`'s accumulated work is eventually released) — this dual-merge requirement is precisely why Module 7's `git cherry-pick` is sometimes used in Git Flow implementations, letting a hotfix's specific commit be applied to both destinations even if they've diverged somewhat.

The complete picture: `main` and `develop` run in parallel indefinitely, with `feature/*` branches feeding into `develop`, `release/*` branches periodically batching `develop`'s accumulated work into an actual, tagged release on `main` (while also syncing back to `develop`), and `hotfix/*` branches providing a fast, direct path for urgent production fixes that bypasses the normal feature/release cycle entirely, but still reaches both `main` and `develop`.

This structure is genuinely powerful for teams needing to maintain a **clear separation between 'in development' and 'released' code**, and for products with a **formal, versioned, periodic release cadence** (rather than continuous deployment) — but it comes with real complexity, requiring every team member to understand and correctly follow five distinct branch types and their specific merge directions, which is exactly the complexity the next lesson's GitHub Flow was designed to simplify away.

Git Flow Branch Structure: Visual Walkthrough

Draw two long horizontal parallel lines: 'main' (top) and 'develop' (bottom), both running left to right. Show 'feature/login' and 'feature/dark-mode' as short branches splitting off 'develop' and merging back INTO develop only. Show 'release/2.4.0' splitting off 'develop', running briefly in parallel, then merging into BOTH 'main' (with a tag icon 'v2.4.0') AND back into 'develop'. Show 'hotfix/payment-crash' splitting DIRECTLY off 'main' (not develop), running briefly, then merging into BOTH 'main' (tag 'v2.4.1') AND 'develop'. Use different colors for each branch type to visually distinguish the five categories.

Git Flow Branch Types: Quick Reference Table

Branch TypeBranches FromMerges IntoPurpose
main(long-running)(represents release history itself)Official, deployable release history
develop(long-running)(represents integration history itself)Latest integrated development work
feature/*developdevelopBuilding one specific new feature
release/*developBOTH main and developStabilizing/finalizing a specific release
hotfix/*mainBOTH main and developUrgently fixing a critical production bug

Git Flow: Command Syntax and Examples

# Feature branch lifecycle
git switch develop
git switch -c feature/user-authentication
# ... work, commit ...
git switch develop
git merge feature/user-authentication
git branch -d feature/user-authentication

# Release branch lifecycle
git switch develop
git switch -c release/2.4.0
# ... final stabilization: bump version numbers, fix minor bugs, update docs ...
git switch main
git merge release/2.4.0
git tag -a v2.4.0 -m "Release version 2.4.0"
git switch develop
git merge release/2.4.0
git branch -d release/2.4.0

# Hotfix branch lifecycle
git switch main
git switch -c hotfix/payment-crash
# ... fix the urgent bug ...
git switch main
git merge hotfix/payment-crash
git tag -a v2.4.1 -m "Hotfix: resolve payment crash"
git switch develop
git merge hotfix/payment-crash
git branch -d hotfix/payment-crash

Breaking Down the Git Flow Example

The feature branch example shows the simplest cycle: branch from `develop`, work, merge back into `develop` only — `main` is never touched. The release branch example demonstrates the defining dual-merge pattern: `release/2.4.0` merges into `main` first (with an accompanying tag, following Module 2's conventions, marking the actual release point), and then separately merges back into `develop` as well, ensuring any stabilization-phase fixes aren't lost. The hotfix example mirrors this same dual-merge pattern, but critically branches directly from `main` (not `develop`) to isolate the urgent fix from any in-progress, potentially unstable `develop` work, then reaches both `main` and `develop` upon completion, exactly as Git Flow's model requires.

How Git Flow Is Used on Real Engineering Teams

  • Git Flow was historically extremely popular, especially for products with a formal, versioned release cycle (like installed desktop software or mobile apps requiring app-store review), where a clear distinction between 'in development' and 'officially released' genuinely matters.
  • Some teams use the git-flow command-line extension tool (a popular third-party wrapper), which automates the branch creation and dual-merge steps described in this lesson, reducing the manual overhead of correctly following the model by hand.
  • In recent years, many teams — especially those practicing continuous deployment rather than periodic, versioned releases — have moved away from Git Flow toward simpler strategies (covered in the next few lessons), specifically citing its complexity and the overhead of maintaining two long-running branches as reasons for switching.
  • Products still shipping discrete, numbered versions (rather than a continuously updated web service) are the segment of the industry where Git Flow's structure remains most clearly well-matched to actual team and release needs.

Git Flow Interview Questions and Answers

Q1. What are the five branch types in Git Flow, and what is each one for?

main represents the official, deployable release history. develop represents the latest integrated development work. feature/* branches build individual new features, branching from and merging back into develop. release/* branches stabilize and finalize a specific release, branching from develop and merging into both main and develop. hotfix/* branches urgently fix critical production bugs, branching from main and also merging into both main and develop.

Q2. Why do release and hotfix branches merge into BOTH main and develop, rather than just one?

Merging into main is what actually ships the change (a release, or an urgent fix) to production. Merging back into develop ensures that any changes made during that branch's lifetime — final stabilization fixes for a release, or the fix itself for a hotfix — aren't lost or later reintroduced as a bug when develop's own accumulated work is eventually released.

Q3. Why does a hotfix branch in Git Flow branch from main rather than develop?

Because develop may contain unstable, in-progress work not yet ready for release, while main represents the last known-good, actually released state. Branching a hotfix directly from main isolates the urgent fix from any potentially unstable in-progress development, ensuring the fix can be shipped quickly without depending on or being entangled with unrelated, unfinished work.

Git Flow Quiz: Test Your Understanding

1. In Git Flow, where do feature branches merge back into?

  1. main only
  2. develop only
  3. Both main and develop
  4. release branches only

Answer: B. develop only

Explanation: Feature branches in Git Flow are created from and merged back into develop exclusively — they never interact directly with main in the standard model.

2. Why does a Git Flow release branch merge into both main and develop?

  1. It's a technical requirement of Git itself
  2. To ship the release on main while also syncing any stabilization fixes back into ongoing development on develop
  3. Because feature branches require this
  4. To automatically delete the develop branch

Answer: B. To ship the release on main while also syncing any stabilization fixes back into ongoing development on develop

Explanation: The dual merge ensures the release is actually shipped (via main) while any last-minute fixes made during the release branch's stabilization phase aren't lost from develop's ongoing history.

3. Where does a hotfix branch originate from in Git Flow, and why?

  1. develop, since that's where all new work starts
  2. main, to isolate the urgent fix from any potentially unstable in-progress work on develop
  3. A release branch, since hotfixes are a type of release
  4. Any branch, chosen at random

Answer: B. main, to isolate the urgent fix from any potentially unstable in-progress work on develop

Explanation: Branching directly from main ensures the hotfix is based on the last known-good, actually released state, rather than potentially unstable, unreleased work that might exist on develop.

Common Mistakes When Using Git Flow

  • Merging a feature branch directly into main instead of develop, violating Git Flow's defined structure.
  • Adding new features to a release branch instead of only performing stabilization work there, blurring the intended separation between feature development and release preparation.
  • Forgetting to merge a hotfix (or release) branch back into develop after merging into main, risking the fix being lost or reintroduced later.
  • Branching a hotfix from develop instead of main, potentially basing an urgent production fix on unstable, unreleased work.

Git Flow: Exam-Ready Quick Notes

  • Git Flow: two long-running branches (main, develop) + three short-lived supporting types (feature/*, release/*, hotfix/*).
  • feature/*: branches from develop, merges into develop only.
  • release/*: branches from develop, merges into BOTH main (tagged) and develop.
  • hotfix/*: branches from main (not develop), merges into BOTH main (tagged) and develop.

Git Flow: Key Takeaways

  • Git Flow's five branch types provide a highly structured model, well suited to products with formal, periodic, versioned releases.
  • The dual-merge pattern for release and hotfix branches (into both main and develop) is Git Flow's key mechanism for keeping released and in-progress history consistent.
  • Git Flow's real complexity — requiring every team member to correctly follow five distinct branch types and merge directions — is exactly what simpler strategies in the following lessons were designed to address.

Frequently Asked Questions About Git Flow

Q1. What are the five branch types in Git Flow?

main (the official release history), develop (the latest integrated development work), feature/* (individual new features), release/* (stabilizing a specific release), and hotfix/* (urgently fixing a critical production bug).

Q2. What is the difference between main and develop in Git Flow?

main represents the official, actually-released history — every commit here corresponds to a shipped version. develop represents the latest integrated development work, where completed features accumulate before being batched into a formal release.

Q3. Why do release branches in Git Flow merge into both main and develop?

Merging into main is what actually ships the release. Merging back into develop ensures any last-minute stabilization fixes made on the release branch (like final bug fixes or version bumps) aren't lost from ongoing development, and won't be accidentally reintroduced later.

Q4. Why does a hotfix branch in Git Flow start from main instead of develop?

Because develop might contain unstable, in-progress work that isn't ready for release, while main represents the last known-good, actually released state. Starting the urgent fix from main keeps it isolated from any unrelated, unfinished work.

Q5. Is Git Flow still commonly used today?

It remains a good fit for products with a formal, periodic, versioned release cycle, but many teams — especially those practicing continuous deployment — have moved toward simpler strategies, specifically because Git Flow's five-branch-type structure involves real complexity and overhead.

Summary

Git Flow defines two long-running branches — `main` (the official, deployable release history) and `develop` (the latest integrated development work) — along with three types of short-lived supporting branches. `feature/*` branches build individual new features, branching from and merging back into `develop` only. `release/*` branches, created from `develop` once enough features have accumulated, handle final stabilization for a specific release, merging into both `main` (shipping the actual release, typically tagged) and back into `develop` (preserving any stabilization fixes). `hotfix/*` branches address urgent production bugs, branching directly from `main` (to isolate the fix from potentially unstable work on `develop`) and, upon completion, also merging into both `main` and `develop`. This structure is well suited to products with a formal, periodic release cadence needing a clear separation between released and in-progress code, but its real complexity — five distinct branch types with specific merge directions every team member must follow correctly — is exactly what simpler strategies covered in the following lessons were designed to address.

Frequently Asked Questions

main (the official release history), develop (the latest integrated development work), feature/* (individual new features), release/* (stabilizing a specific release), and hotfix/* (urgently fixing a critical production bug).

main represents the official, actually-released history — every commit here corresponds to a shipped version. develop represents the latest integrated development work, where completed features accumulate before being batched into a formal release.

Merging into main is what actually ships the release. Merging back into develop ensures any last-minute stabilization fixes made on the release branch (like final bug fixes or version bumps) aren't lost from ongoing development, and won't be accidentally reintroduced later.

Because develop might contain unstable, in-progress work that isn't ready for release, while main represents the last known-good, actually released state. Starting the urgent fix from main keeps it isolated from any unrelated, unfinished work.

It remains a good fit for products with a formal, periodic, versioned release cycle, but many teams — especially those practicing continuous deployment — have moved toward simpler strategies, specifically because Git Flow's five-branch-type structure involves real complexity and overhead.