Lesson 06
A structured branching model for predictable, parallel development
Without a branching strategy, teams stumble over each other. Code gets lost, deployments break, and nobody knows what is in production. A well-defined branching model gives you:
GitFlow is not the only branching model (trunk-based development is popular for CI/CD-heavy teams), but it excels when you need structured releases and multiple parallel streams of work.
GitFlow defines five distinct branch types, each with a clear purpose and lifecycle.
| Branch | Purpose | Created From | Merges Into | Lifetime |
|---|---|---|---|---|
main |
Production-ready code | — | — | Permanent |
develop |
Integration branch | main |
— | Permanent |
feature/* |
New functionality | develop |
develop |
Short-lived |
release/* |
Release preparation | develop |
main + develop |
Short-lived |
hotfix/* |
Emergency production fix | main |
main + develop |
Short-lived |
main only receives merges from release and hotfix branches. develop is the central hub where features land. Feature branches are short-lived and merge back into develop via pull requests.
Consistent naming makes branches searchable, sortable, and self-documenting.
type/TICKET-ID-short-description# Feature branches
feature/STORY-123-user-authentication
feature/STORY-456-export-csv
# Release branches
release/v1.2.0
release/v2.0.0-beta
# Hotfix branches
hotfix/FIX-789-null-pointer-crash
hotfix/FIX-012-security-patch
Use lowercase, hyphens (not underscores), and keep descriptions under 5 words. Always include the ticket ID so branches are traceable back to your backlog.
The agile framework provides commands that follow this branching model. Use /agile-code-branch to create properly named branches and /agile-code-merge to merge with the correct strategy. These commands prompt you for required inputs like branch type, ticket ID, and merge strategy.
git checkout develop
git pull origin develop
git checkout -b feature/STORY-123-add-login
# Work in small, focused commits
git add src/auth/login.ts
git commit -m "feat(auth): add login form component"
git add src/auth/login.test.ts
git commit -m "test(auth): add login form unit tests"
git push origin feature/STORY-123-add-login
# Open PR: feature/STORY-123-add-login → develop
# Get code review, pass CI checks
# Squash merge for a clean history
git checkout develop
git merge --squash feature/STORY-123-add-login
git commit -m "feat(auth): add login form (#123)"
git branch -d feature/STORY-123-add-login
git checkout develop
git checkout -b release/v1.2.0
# Bump version, update changelog, final QA
git checkout main
git merge --no-ff release/v1.2.0
git tag -a v1.2.0 -m "Release v1.2.0"
git push origin main --tags
# Back-merge to develop
git checkout develop
git merge --no-ff release/v1.2.0
git branch -d release/v1.2.0
# Create hotfix branch from main
git checkout main
git pull origin main
git checkout -b hotfix/FIX-789-null-pointer-crash
# Fix the bug, commit
git add src/auth/session.ts
git commit -m "fix(auth): handle null session on token refresh"
# Merge hotfix into main with --no-ff
git checkout main
git merge --no-ff hotfix/FIX-789-null-pointer-crash
git tag -a v1.2.1 -m "Hotfix v1.2.1"
git push origin main --tags
# Back-merge hotfix into develop with --no-ff
git checkout develop
git merge --no-ff hotfix/FIX-789-null-pointer-crash
git branch -d hotfix/FIX-789-null-pointer-crash
Hotfixes always use --no-ff when merging into both main and develop. Never squash-merge a hotfix — the merge commit preserves traceability and makes the fix visible in the branch history.
We follow Conventional Commits to make history readable and enable automated changelogs.
| Prefix | Purpose | Example |
|---|---|---|
feat: | New feature | feat(cart): add quantity selector |
fix: | Bug fix | fix(auth): handle expired tokens |
refactor: | Code restructuring (no behavior change) | refactor(api): extract validation middleware |
test: | Adding or updating tests | test(cart): add edge case for empty cart |
docs: | Documentation changes | docs(readme): update setup instructions |
perf: | Performance improvement | perf(query): add index for user lookup |
chore: | Build, tooling, dependencies | chore(deps): update lodash to 4.17.21 |
Never mix structural changes (refactor:, renames, moves) with behavioral changes (feat:, fix:) in the same commit. This makes reverts safe and code review focused.
Condenses all feature commits into a single commit on develop. Keeps the integration branch clean and readable.
git merge --squash feature/STORY-123-add-login
Preserves the branch structure in history. You can always see where a release or hotfix started and ended.
git merge --no-ff release/v1.2.0
main or develop. These are protected branches.The agile framework provides commands that implement this branching model. Each command prompts you for the required inputs.
| Command | GitFlow Step | What You Provide |
|---|---|---|
/agile-code-branch | Create feature, release, or hotfix branch | Branch type, ticket ID, description |
/agile-code-tdd | Develop with tests (on feature branch) | Feature requirements, test cases |
/agile-code-ci | Verify CI passes before merge | CI configuration, fix guidance |
/agile-code-commit | Commit with conventional format | Change description, scope |
/agile-code-pr | Open pull request | PR description, reviewers |
/agile-code-pr-review | Review the pull request | Review criteria, feedback |
/agile-code-merge | Merge with correct strategy | Target branch, merge strategy |
/agile-ship-hotfix | Emergency hotfix workflow | Bug description, severity |
/agile-ship-release | Release branch workflow | Version, changelog entries |
/agile-ship-changelog | Generate changelog from commits | Version range, format |
Where do feature branches merge into?