Git Flow in practice: feature, release, and hotfix
A straightforward guide to Git Flow: the role of each branch, the commands for each flow, naming and versions, when the model is worth it, and when trunk-based or GitHub Flow fits better.
Git Flow is a branching model proposed by Vincent Driessen in 2010. The idea is simple: each branch has a fixed role. That makes it clear what's in production, what goes into the next version, and what's an urgent fix.
In this guide you'll see what each branch is for, the commands for each flow, how to name branches and versions, the most common mistakes, and the kind of project where the model really helps.
The Git Flow branches
main: what's in production. Each merge here becomes a version, marked with a tag.develop: where features come together before the next version.feature/*: branch offdevelopand go back intodevelopwhen they're done.release/*: branch offdevelopto prepare a version. They go back intomainanddevelop.hotfix/*: branch offmainto fix production. They go back intomainanddevelop.
main and develop live forever. The others are temporary: they're created, do their job, and get deleted.
The feature flow
A feature starts from develop, gets the commits for the work, and goes back into develop with a merge:
git switch develop
git pull
git switch -c feature/login-sso
# feature commits
git switch develop
git merge --no-ff feature/login-sso
git branch -d feature/login-sso
git push origin develop--no-ff creates a merge commit even when Git could just move the pointer forward. That way the history shows where the feature started and where it ended, which helps a lot when you need to review or revert the whole feature.
On teams that use pull requests, the merge into develop usually happens on GitHub, GitLab, or Azure DevOps after review. The logic is the same.
Closing a release
When develop has what should ship in the next version, open a release branch. From then on the scope is frozen: only fixes, the version number bump, and the changelog go in.
git switch -c release/1.4.0 develop
# final tweaks, version, and changelog
git switch main
git merge --no-ff release/1.4.0
git tag -a v1.4.0 -m "Version 1.4.0"
git switch develop
git merge --no-ff release/1.4.0
git branch -d release/1.4.0
git push origin main develop --tagsWhile the release is open, the team can keep starting features on develop. They only go into the following version.
Fixing production with a hotfix
A hotfix follows the same logic, but it starts from main, because it needs to fix exactly what's in production:
git switch -c hotfix/1.4.1 main
# fix
git switch main
git merge --no-ff hotfix/1.4.1
git tag -a v1.4.1 -m "Version 1.4.1"
git switch develop
git merge --no-ff hotfix/1.4.1
git branch -d hotfix/1.4.1Bringing the fix into develop is the step people forget most. It's what keeps the bug from coming back in the next version. If there's a release open, merge the hotfix into it instead of develop.
Branch names and versions
- Use fixed prefixes:
feature/,release/, andhotfix/. Tools and pipelines depend on them. - For a feature, describe the topic or use the task number:
feature/login-ssoorfeature/1234-login-sso. - For a release or hotfix, use the version number:
release/1.4.0andhotfix/1.4.1. - Follow semantic versioning: the third number goes up for fixes, the second for compatible new features, and the first for breaking changes.
Git Flow, GitHub Flow, or trunk-based?
- Git Flow: good for products with numbered versions, desktop and mobile apps, libraries, and systems that maintain more than one version in parallel.
- GitHub Flow: just
mainand short branches with pull requests. Good for web applications deployed several times a week. - Trunk-based: everyone integrates into
mainseveral times a day, with feature flags to hide what isn't ready. Good for mature teams with strong automated tests.
No model is right for everyone. If your team deploys to production several times a day, Git Flow will feel bureaucratic. If you ship versions for customers to install, it brings a lot of order to the work.
The most common mistakes
- Forgetting to bring the hotfix back into
develop. - Leaving the release open for weeks, until it turns into a second
develop. - Features that live a long time without pulling in
developand pile up conflicts. - Committing directly to
mainordevelopwithout going through a branch. - Forgetting to create the tag, which leaves the production version with no reference in the history.
Git Flow in GitMuninn
On the Pro plan, GitMuninn starts and finishes features, releases, and hotfixes with the prefixes your repository already uses, so you don't have to memorize the command sequence. And since each branch has its own color in the graph, it's easy to see whether a hotfix has already gone back into develop or whether a release is still open.

