CS

Git Flow

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.

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