Git flow is a branching model that defines specific rules for how branches should be created, named, and merged. It’s designed to help manage features and releases more predictably in larger projects.
Let’s see it in action. Imagine a new feature, "User Profile Editing," needs to be developed.
# Start on the main development branch
git checkout develop
# Create a new feature branch from develop
git checkout -b feature/user-profile-editing develop
# Make some changes
echo "<h1>User Profile</h1>" > profile.html
git add profile.html
git commit -m "Add initial profile structure"
# Later, more changes
echo "<p>Edit your details here.</p>" >> profile.html
git add profile.html
git commit -m "Add editing functionality"
Once the feature is complete, it’s merged back into develop.
# Switch back to develop
git checkout develop
# Merge the completed feature branch
git merge --no-ff feature/user-profile-editing
# Clean up the feature branch
git branch -d feature/user-profile-editing
The --no-ff (no fast-forward) option is crucial here. It ensures that a merge commit is always created, even if the branch could be fast-forwarded. This preserves the history of the feature branch, making it clear when a feature was developed and merged.
Now, let’s say we want to prepare for a release. A release branch is created from develop.
# Create a release branch
git checkout -b release/v1.1.0 develop
On this release branch, only bug fixes and documentation updates are allowed. No new features are added.
# Fix a bug found during release testing
echo "<!-- Fix: Corrected typo -->" >> release_notes.md
git add release_notes.md
git commit -m "Fix typo in release notes"
When the release is ready, it’s merged into both main (for production) and develop (to incorporate any last-minute fixes).
# Switch to main
git checkout main
# Merge the release branch into main
git merge --no-ff release/v1.1.0
# Tag the release
git tag -a v1.1.0 -m "Version 1.1.0"
# Switch back to develop
git checkout develop
# Merge the release branch into develop
git merge --no-ff release/v1.1.0
# Clean up the release branch
git branch -d release/v1.1.0
This process ensures that main always reflects stable, production-ready code, while develop is where ongoing development happens.
The hotfix branch is another key component, used for urgent production bug fixes. It’s branched directly from main.
# Imagine a critical bug found in production v1.1.0
git checkout -b hotfix/critical-bug main
# Fix the bug
sed -i 's/old_buggy_code/new_fixed_code/g' production_file.js
git add production_file.js
git commit -m "Fix critical bug in production"
Like a release branch, a hotfix is merged into both main and develop.
# Switch to main
git checkout main
# Merge the hotfix
git merge --no-ff hotfix/critical-bug
# Tag the new patch version
git tag -a v1.1.1 -m "Version 1.1.1 - Critical bug fix"
# Switch back to develop
git checkout develop
# Merge the hotfix into develop
git merge --no-ff hotfix/critical-bug
# Clean up the hotfix branch
git branch -d hotfix/critical-bug
This flow creates a clear separation between long-term development, feature work, planned releases, and urgent fixes.
The most surprising thing about Git Flow is how rigidly it enforces a workflow that, on the surface, seems overly complex for small teams. Yet, the discipline it imposes on branch management is precisely what prevents the cascading merge conflicts and release chaos that plague less structured approaches as projects scale. It’s not about the commands themselves, but the predictable lifecycle they enable for code.
One thing most people don’t realize is that the develop branch isn’t just a dumping ground for unfinished features; it’s the official integration branch for all completed features and the source for all release branches. This means develop should ideally be in a state where it could be released at any moment, albeit perhaps with fewer features than the final release.
Understanding how to effectively use git flow on the command line, or with a tool like git-flow-avh, is the next step to mastering this branching strategy.