CS

Git Flow Guide — Feature & Hotfix Branches

The Gitflow branching model: main/develop plus feature, release, and hotfix branches — with commands, a branch reference, and when NOT to use it.

What this covers

The Gitflow branching model — two long-lived branches (main, develop) plus three kinds of short-lived support branches (feature/*, release/*, hotfix/*) — and the commands to drive each one. It also covers, honestly, when Gitflow is the wrong choice. For everyday git commands see Git ; for running branches in parallel working directories see Git Worktrees .

When to use it

  • Deciding where a change should branch from and merge back to under Gitflow
  • Starting a feature, cutting a release, or shipping an emergency hotfix
  • Setting up a release-oriented branching model for a versioned product
  • Deciding whether Gitflow or a simpler model (trunk-based, GitHub Flow) fits the team

The branches

  • main — production. Every commit is a released, tagged version.
  • develop — integration branch. Completed features land here first.
  • feature/* — one per unit of work; branches from and merges back to develop.
  • release/* — branches from develop to stabilise a version; merges to both main and develop.
  • hotfix/* — branches from main to fix production; merges to both main and develop.

You can drive Gitflow with plain git (shown below, works anywhere) or with the git flow command-line extension, which wraps the same steps.

When NOT to use Gitflow

Worth being honest — Gitflow is often the wrong default for modern web work.

  • Continuously-deployed web apps / SaaS: prefer trunk-based development or GitHub Flow — short-lived branches off main, merge and deploy. Gitflow’s long-lived develop and release branches add ceremony a deploy-on-merge pipeline doesn’t need.
  • Small teams / solo projects: the overhead rarely pays for itself.
  • If you deploy main many times a day, the develop/release split works against you.

Gitflow earns its keep when you ship discrete, versioned releases (installed software, mobile apps, libraries, on-prem products) and may need to support more than one version at a time.

Setup

# Plain git: create the develop branch off main once
git switch main
git switch -c develop
git push -u origin develop

# Or with the git flow extension (interactive; accept defaults)
git flow init

Feature branches

Branch from develop, merge back to develop. Never branch a feature from main.

# Start
git switch develop
git pull
git switch -c feature/short-description

# ... commit work ...

# Finish — integrate back into develop
git switch develop
git pull
git merge --no-ff feature/short-description
git push
git branch -d feature/short-description

# git flow equivalent
git flow feature start short-description
git flow feature finish short-description

--no-ff keeps the feature’s commits grouped under a merge commit, so the branch’s shape stays visible in history.

Release branches

Branch from develop when the release scope is frozen. Only stabilisation commits (version bump, changelog, bug fixes) go here — no new features. Merge to both main and develop, and tag main.

# Start
git switch develop
git pull
git switch -c release/1.4.0
# ... bump version, update changelog, fix release-blocking bugs ...

# Finish
git switch main
git merge --no-ff release/1.4.0
git tag -a v1.4.0 -m "Release 1.4.0"

git switch develop
git merge --no-ff release/1.4.0   # so fixes made on the release branch return to develop

git push origin main develop --tags
git branch -d release/1.4.0

# git flow equivalent
git flow release start 1.4.0
git flow release finish 1.4.0     # merges to main + develop and tags

Merging the release back into develop is the step people forget — skip it and the release-branch bug fixes vanish from ongoing development.

Hotfix branches

For an urgent production fix. Branch from main, merge to both main and develop, and tag main with a new patch version.

# Start from production
git switch main
git pull
git switch -c hotfix/1.4.1
# ... fix the bug ...

# Finish
git switch main
git merge --no-ff hotfix/1.4.1
git tag -a v1.4.1 -m "Hotfix 1.4.1"

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

git push origin main develop --tags
git branch -d hotfix/1.4.1

# git flow equivalent
git flow hotfix start 1.4.1
git flow hotfix finish 1.4.1

If a release/* branch is open when you hotfix, merge the hotfix into the release branch instead of develop (the release branch carries it back to develop on finish) — otherwise you merge the same fix twice.

Branch reference

BranchBranches fromMerges back toTagged?
feature/*developdevelopno
release/*developmain and developyes (on main)
hotfix/*mainmain and developyes (on main)

Safety rules

  • main is always releasable. Only merge release/* or hotfix/* into it, always tagged.
  • No features on release/* or hotfix/* — only stabilisation/fix commits.
  • Always merge release and hotfix branches back into develop, or the fixes are lost from ongoing work.
  • Use --no-ff for support-branch merges so history shows where each branch integrated.
  • Tag every main merge with a semantic version — the tag is the released artifact’s identity.

Common mistakes

  • A feature branch that lives for weeks. The longer it drifts from develop, the worse the final merge. Merge develop into it regularly and split the work into smaller features.
  • New features on the release branch. A release branch is there to stabilise a version; every added feature sends stabilisation back to the start.
  • Hotfix straight on main. Without a hotfix/* branch the fix easily never reaches develop, and the bug returns in the next version.
  • Missing tag. A merge into main without a tag means nobody can tell which commit is which version.
  • Fast-forward merges of support branches. Without --no-ff the feature’s boundary disappears from history and it cannot be reverted in one commit.
  • Gitflow “because that is how it is done”. On a website deployed on every merge, develop is just one more branch to keep in sync.

Troubleshooting

SymptomCause / fix
Release-branch fix missing from new featuresRelease branch wasn’t merged back into develop — merge it now
Same hotfix applied twice, merge conflictHotfix merged to both develop and an open release/* — merge to the release branch only; it carries to develop on finish
develop far ahead of main, never releasingDeploy cadence outpaces the model — reconsider trunk-based / GitHub Flow
git flow command not foundInstall the extension (git-flow / git-flow-avh package), or use the plain-git steps above
Feature accidentally branched from mainRebase it onto develop: git rebase --onto develop main feature/x

Frequently asked questions

What is Git Flow?

Git Flow (Gitflow) is a branching model with two permanent branches — main for released versions and develop for integration — and three kinds of temporary branches: feature/*, release/* and hotfix/*. Each kind has a fixed place to branch from and to merge into.

What is the difference between Git Flow and GitHub Flow?

GitHub Flow has a single permanent branch, main: short branch, pull request, merge, deploy. Git Flow adds develop and release branches, which suits products shipped in versions; for a website deployed on every merge it is overhead.

Do I need to install the git flow extension?

No. Commands such as git flow feature start only wrap plain git switch, git merge --no-ff and git tag. The whole model runs on plain git; the extension saves typing and keeps the steps in order.

Where does a hotfix branch from, and where is it merged?

A hotfix branches from main, because it fixes what runs in production. Once fixed, it is merged into main (tagged with the new patch version) and back into develop — or into the open release/* branch, if there is one.

Is Git Flow outdated?

Not outdated, just not a fit everywhere. For continuously deployed websites and SaaS, trunk-based development or GitHub Flow is simpler. For libraries, mobile apps and on-prem software with numbered versions, Git Flow still makes sense.