In Git, which branches does the Git Flow model define and what is each one for?
answer
- Count the branches that live forever
- Two permanent lines, three temporary types
- One branch integrates, one only records releases
- Hotfixes start where production is
- Releases and hotfixes land in two places
basics
~20 sGit Flow defines two permanent branches, main and develop, plus three temporary types: feature branches cut from develop, release branches cut from develop, and hotfix branches cut from main. Releases and hotfixes merge back into both permanent branches.
solid answer
~40 sGit Flow prescribes five branch roles over ordinary Git branches. **main** holds only released code and is normally tagged at each release; nobody commits to it directly. **develop** is the integration branch where finished work accumulates between releases. **Feature branches** start from `develop` and merge back into `develop`. **Release branches** start from `develop` when scope is frozen, take only stabilization commits, and merge into `main` *and* back into `develop`. **Hotfix branches** start from `main`, because they patch what is in production, and also merge into both. The double merge is the point people miss: `main` and `develop` are separate lines of history, so a fix landed on one is simply absent from the other until it is merged there too.
go deeper
Be ready to name all five roles and say where each branch starts and ends. The two you must not mix up: features come off develop, hotfixes come off main.
Explain why the hotfix and release merges go into both permanent branches, and what divergence between main and develop means in three-way-merge terms.
Expect to justify the model against a team's release cadence, and to describe the conflict cost that accumulates while develop runs ahead of main between releases.
Own the argument for when the ceremony pays for itself: several supported versions in the field justify the extra branch set, a single continuously deployed service does not.
## What Git Flow actually is Git Flow is a branching model published by Vincent Driessen in 2010. Git itself knows nothing about it: every branch below is an ordinary Git branch — a movable pointer to a commit — and the model is a naming convention plus rules about where a branch starts and where it merges back. There is an optional third-party helper script invoked as `git flow`, distributed separately from Git, but the whole model works with nothing but `git branch`, `git merge` and `git tag`. ## The two permanent branches **main** (called `master` in the original article) contains only code that has been released. Each commit on it corresponds to a shipped version and is normally marked with an annotated tag. No one commits to `main` directly; commits arrive only by merging a release branch or a hotfix branch. **develop** is the integration branch. Finished features accumulate there between releases, so its tip means "the next release, so far". Day-to-day work in a Git Flow repository starts from `develop`, not from `main`. Because both branches live forever, they permanently diverge and re-converge. `git log main..develop` almost always lists commits — that is the model working as designed, not a problem to fix. ## The three supporting branch types **Feature branches** start from `develop` and merge back into `develop`, conventionally named `feature/<something>`. Work on a feature branch never touches `main` directly. **Release branches** are cut from `develop` once the team fixes the scope of the next version, conventionally `release/1.4.0`. Only stabilization commits belong there — bug fixes, version bumps, changelog edits — while new features keep landing on `develop` in parallel. When the version ships, the release branch merges into `main` (which is then tagged) and back into `develop`, and is deleted. **Hotfix branches** start from `main`, not from `develop`, because they fix what is running in production right now, and unreleased work on `develop` must not be dragged along. Conventionally `hotfix/1.4.1`. They merge into `main`, which is tagged again, and into `develop`. ## Why releases and hotfixes merge in two directions This double merge is the structural heart of the model. `main` and `develop` are different lines of history; a commit merged into one is not present in the other. If a hotfix landed only on `main`, the next release branch — cut from `develop` — would not contain the fix, and shipping it would reintroduce the very bug that was just patched in production. Merging the hotfix into `develop` as well makes the fix an ancestor of both lines, so later merges treat it as already integrated instead of as a conflicting change. The same argument applies to a release branch: stabilization commits made on it must travel back to `develop`, or they are lost at the next release. ## What Git does at each step Every step is a plain three-way merge, using the commit where the branch diverged as the merge base. Git Flow conventionally uses `git merge --no-ff`, which records a merge commit even when the target could simply fast-forward. The effect is that each feature shows up in history as one merge commit with its own commits on a side branch, so `git log --first-parent develop` reads as a list of features rather than a flat stream of individual commits. Deleting a feature or release branch after the merge loses nothing. The commits remain reachable through the merge commit; only the pointer disappears. ## Where the model fits Git Flow was designed for software with explicit, versioned releases — desktop applications, libraries, on-premises products, anything where several versions exist in the field at once. The release branch gives a place to stabilize while feature work continues; the hotfix branch gives a way to patch what shipped without shipping anything unreleased. It fits a service deployed many times a day badly: `develop` is then never meaningfully ahead of `main`, and every change pays for a second merge and a branch that exists for minutes. Driessen later added a reflection note to the original article steering continuously delivered web applications toward simpler, single-main workflows. ## The vocabulary trap Being able to say that `git flow` (the helper script) and Git Flow (the model) are different things — and that Git ships neither — is what separates someone who understands the model from someone who has memorized a tool's menu.
- Why does Git Flow prescribe `git merge --no-ff` when merging a feature branch into develop?Without it, Git fast-forwards when `develop` has not moved, and the feature's commits blend into a flat line with no record that they belonged together. `--no-ff` forces a merge commit, so `git log --first-parent develop` reads as one entry per feature and `git revert -m 1` on that merge can back the whole feature out.
- What breaks if a hotfix is merged into main but never into develop?The fix exists only on the released line. The next release branch is cut from `develop`, which does not contain it, so the shipped version reintroduces the bug. Worse, when that release later merges into `main`, Git sees two histories that changed the same lines differently and you get a conflict at the least convenient moment.
- Does deleting a release branch after merging lose the stabilization commits?No. Those commits are reachable as parents of the merge commits on `main` and `develop`, so they stay in history and in `git log`. A branch name is only a pointer; deleting it removes the label, not the objects. Only commits that no ref can reach eventually become candidates for garbage collection.
saying these in an interview costs you the question
- Says Git Flow defines only main and develop
- Thinks feature branches are cut from main
- Claims a hotfix only needs merging into main
- Calls release branches permanent, long-lived branches
- Believes git ships a built-in flow subcommand