Git Flow Branching Strategy
This document defines the branching strategy for NeuraFlow, following the Git Flow model by Vincent Driessen.
Reference: A successful Git branching model
Overview
Git Flow uses two permanent branches and three types of supporting branches to manage development, releases, and hotfixes.
Branch Structure
Permanent Branches
| Branch | Purpose | Protection |
|---|---|---|
main | Production-ready code. Each commit represents a release. | Protected. No direct commits. |
develop | Integration branch containing latest development changes. | Protected. Only merge from feature/release/hotfix. |
Supporting Branches
| Type | Branch From | Merge To | Naming | Lifecycle |
|---|---|---|---|---|
| Feature | develop | develop | feature/* | Temporary. Delete after merge. |
| Release | develop | main AND develop | release/* | Temporary. Delete after merge. |
| Hotfix | main | main AND develop | hotfix/* | Temporary. Delete after merge. |
Core Concept: No Fast-Forward Merges
Always use --no-ff flag to preserve branch history and enable clean reverts.
Fast-Forward Merge (Default Behavior - Avoid)
Result: main → A → B → C → D (Linear - no branch information preserved)
Problem: Cannot identify which commits (C, D) belonged to the feature branch.
No Fast-Forward Merge (Use --no-ff - Preferred)
Result: main → A → B → M with feature branch B → C → D → M preserved
Advantage: Merge commit (M) preserves branch structure. Easy to identify feature commits (C, D).
Legend: 🔵 Main commits | 🔴 Feature commits | 🟢 Merge commit
Benefits
- Preserves context - Branch history remains visible
- Atomic reverts - Revert entire feature:
git revert -m 1 <merge-commit> - Clear audit trail - Track what was merged and when
- Groups changes - Related commits stay together
Workflows
Feature Development
# Create feature
git checkout develop
git pull origin develop
git checkout -b feature/my-feature
# Develop and commit
git add .
git commit -m "feat: add feature description"
# Merge to develop
git checkout develop
git merge --no-ff feature/my-feature
git branch -d feature/my-feature
git push origin develop
Keeping Feature Branch Up to Date
When develop receives critical changes (e.g., bug fixes, shared API changes, or dependency updates) that your feature branch depends on, rebase your feature branch onto the latest develop:
Before rebase — feature branch is behind develop:
Legend: 🔵 Develop commits | 🔴 Feature commits
After git rebase origin/develop — feature commits replayed on top of latest develop:
Legend: 🔵 Develop commits | 🟢 Rebased feature commits
Commits
C',E', andH'are new commits with the same changes asC,E, andH, but replayed on top ofG.
# Fetch latest changes
git fetch origin
# Rebase feature branch onto latest develop
git checkout feature/my-feature
git rebase origin/develop
# Resolve conflicts if any, then continue
git rebase --continue
# Force push if the branch was already pushed to remote
git push --force-with-lease origin feature/my-feature
Note: Use
--force-with-leaseinstead of--forceto safely push rebased branches. It will abort if the remote has changes you haven't seen, preventing accidental overwrites.
Warning: Do not rebase branches that multiple developers are actively working on. In that case, use
git merge developinto the feature branch instead to avoid rewriting shared history.
Release Process
# Create release branch
git checkout develop
git checkout -b release/1.2.0
# Prepare release (bump version, fix bugs, update docs)
git commit -m "chore: bump version to 1.2.0"
# Merge to main
git checkout main
git merge --no-ff release/1.2.0
git tag -a v1.2.0 -m "Release version 1.2.0"
git push origin main --tags
# Merge to develop
git checkout develop
git merge --no-ff release/1.2.0
git push origin develop
# Clean up
git branch -d release/1.2.0
⚠️ Critical: Merge to Both Branches Individually
Incorrect Approach:
# ❌ WRONG - Do not merge main into develop
git checkout main
git merge --no-ff release/1.2.0
git checkout develop
git merge --no-ff main # Never do this
Correct Approach:
# ✅ CORRECT - Merge release branch to both targets
git checkout main
git merge --no-ff release/1.2.0
git checkout develop
git merge --no-ff release/1.2.0 # Merge release, not main
Rationale:
developmay contain new features committed during release preparation- Merging
releaseto both branches applies only release changes - Merging
main → developcould introduce unintended changes - Clearer conflict resolution with specific release changes
- Explicit intent improves history readability
Hotfix Process
# Create hotfix
git checkout main
git checkout -b hotfix/1.2.1
# Fix the issue
git commit -m "fix: critical bug description"
# Merge to main
git checkout main
git merge --no-ff hotfix/1.2.1
git tag -a v1.2.1 -m "Hotfix version 1.2.1"
git push origin main --tags
# Merge to develop
git checkout develop
git merge --no-ff hotfix/1.2.1
git push origin develop
# Clean up
git branch -d hotfix/1.2.1
Best Practices
- Always use
--no-ff- Preserve branch history for all merges - Protect main branches - Require pull requests for
mainanddevelop - Tag all releases - Use semantic versioning (e.g.,
v1.2.3) - Short-lived branches - Merge features frequently to avoid conflicts
- Never commit directly - Use branches for all changes
- Test before merging - Validate on release branches before production
Commit Message Convention
Follow Conventional Commits specification:
| Type | Description | Example |
|---|---|---|
feat | New feature | feat: add user authentication |
fix | Bug fix | fix: resolve login timeout |
docs | Documentation | docs: update API guide |
style | Code formatting | style: format with prettier |
refactor | Code restructuring | refactor: extract validation logic |
test | Tests | test: add unit tests for auth |
chore | Maintenance | chore: update dependencies |
Releasing New Versions
Client (Frontend)
Update version in package.json and merge to main:
cd client
npm version patch # For bug fixes (2.2.0 → 2.2.1)
npm version minor # For new features (2.2.0 → 2.3.0)
npm version major # For breaking changes (2.2.0 → 3.0.0)
git add package.json
git commit -m "chore: bump client version to v2.3.0"
git push origin develop
# Create PR to main, merge when ready
# GitHub Actions automatically tags image as :v2.3.0 and :latest
Server (Backend)
Create git tag and merge to main:
git tag -a v1.5.0 -m "Release version 1.5.0"
git push origin v1.5.0
# Create PR to main, merge when ready
# GitHub Actions automatically tags image as :v1.5.0 and :latest
Docker Image Tags
| Branch | Tags Generated | Environment |
|---|---|---|
develop | :develop | Staging/Testing |
main | :v1.5.0, :latest | Production |
Deployment Examples:
# Staging (auto-updates)
docker pull ghcr.io/brain-station-23/neuraflow/server:develop
# Production (specific version)
docker pull ghcr.io/brain-station-23/neuraflow/server:v1.5.0
# Production (latest)
docker pull ghcr.io/brain-station-23/neuraflow/server:latest
When to Use Git Flow
Best suited for:
- Projects with scheduled releases
- Software requiring multiple production versions
- Teams coordinating parallel feature development
Consider alternatives for:
- Continuous deployment (use GitHub Flow)
- Small teams with simple workflows
- Projects requiring rapid iteration