What Is the Feature Branch Workflow?
The workflow has three non-negotiable rules:
- main is always deployable — every commit on main could theoretically be deployed to production right now
- No direct commits to main — all changes go through a branch and a pull request
- PRs require code review and CI checks before merging
Everything else — how you name branches, how many reviewers a PR needs, squash vs merge commits — is team convention built on top of these three rules.
Core Rules Explained
When main is always deployable, you can respond to a production outage at any time. You don't need to find a "safe" point in history to roll back to — main IS the safe point. This discipline also catches integration problems early: when your feature branch is merged, any breakage is immediately visible and attributed to that specific merge.
Step-by-Step Workflow
# Step 1: Start from the latest main
git switch main
git pull origin main
# Step 2: Create a descriptive feature branch
git switch -c feature/user-profile-page
# Step 3: Work on the feature — commit early and often
git add src/pages/UserProfile.js
git commit -m "feat(profile): add user profile page skeleton"
git add src/pages/UserProfile.js src/api/users.js
git commit -m "feat(profile): connect profile page to users API"
git add src/pages/UserProfile.css
git commit -m "style(profile): add responsive layout for profile page"
# Step 4: Keep your branch up to date with main to avoid big conflicts
git fetch origin
git rebase origin/main # or: git merge origin/main
# Step 5: Push your branch to the remote
git push -u origin feature/user-profile-page
# -u sets the upstream — future pushes only need: git push
# Step 6: Open a Pull Request on GitHub/GitLab
# - Write a clear PR title and description
# - Link to the related issue (#42)
# - Request reviewers
# CI/CD automatically runs tests on your branch
# Step 7: Address review comments
git add src/pages/UserProfile.js
git commit -m "fix(profile): address code review feedback"
git push
# Step 8: After PR is approved and CI passes — merge!
# (Done via GitHub/GitLab UI — squash merge or regular merge)
# Step 9: Clean up — delete the feature branch
git switch main
git pull origin main
git branch -d feature/user-profile-page
Branch Naming Conventions
Consistent branch naming helps the whole team understand what's being worked on at a glance:
| Prefix | Used for | Example |
|---|---|---|
feature/ | New features | feature/user-authentication |
bugfix/ | Bug fixes in development | bugfix/login-null-pointer |
hotfix/ | Urgent production fixes | hotfix/payment-crash-v2.1 |
chore/ | Maintenance, config, tooling | chore/upgrade-dependencies |
docs/ | Documentation only changes | docs/update-api-readme |
refactor/ | Code refactoring | refactor/extract-auth-service |
Many teams include the issue/ticket number: feature/GH-42-user-profile or bugfix/JIRA-1234-fix-payment. This creates an instant link between the branch and the requirements/bug report, and GitHub automatically links commits to issues when the branch name contains the issue number.
The Pull Request Process
A good pull request makes the reviewer's job easy:
- Title: short, imperative mood — "Add user profile page" (not "Added" or "Adding")
- Description: what changed, why, how to test it, screenshots for UI changes
- Link to issue: "Closes #42" in the description auto-closes the issue on merge
- Small scope: a PR should do one thing — a 500-line PR is hard to review; ten 50-line PRs are much better
- CI/CD must pass: never merge a red PR
Trunk-Based Development — The Even Simpler Version
Trunk-based development is a variation where feature branches are extremely short-lived (less than a day) or developers commit directly to main using feature flags to hide incomplete features from users:
// Feature flag pattern — incomplete feature is in main but hidden
if (featureFlags.isEnabled('new-dashboard')) {
return <NewDashboard />;
}
return <OldDashboard />;
Workflow Comparison
| Aspect | Git Flow | Feature Branch (GitHub Flow) | Trunk-Based |
|---|---|---|---|
| Permanent branches | main + develop | main only | main only |
| Branch lifespan | Days to weeks | Hours to days | Hours or none |
| Release cadence | Versioned releases | Continuous | Continuous (multiple/day) |
| Complexity | High | Medium | Low |
| Best for | Versioned software | Most web teams | Elite DevOps teams |
The Feature Branch Workflow, Step by Step
This is the workflow most teams use: main always stays deployable, and every piece of work happens on its own short-lived branch that merges back via a pull request. No one commits directly to main.
# 1. start fresh from up-to-date main
git switch main
git pull
# 2. branch for the task
git switch -c feature/user-search
# 3. work in small commits
git add . && git commit -m "feat: add search box"
# 4. push and open a pull request
git push -u origin feature/user-search
# 5. after review + CI pass, merge to main, then delete the branch
| Step | Why |
|---|---|
| branch off latest main | minimize divergence/conflicts |
| pull request | code review + automated CI checks |
| delete after merge | keep the branch list clean |
What makes it work: the pull request is a quality gate — teammates review the diff and CI runs tests before anything reaches main, so the main line stays releasable at all times. Keep branches small and short-lived: a branch open for weeks drifts from main and merges painfully. If main moves while you work, git pull then merge (or rebase) it into your branch early to resolve conflicts in small pieces rather than one giant clash at the end.
🏋️ Practical Exercise
- Create a feature branch off main.
- Commit focused work on it.
- Push and open a Pull Request.
- Merge and delete the branch.
- Keep main always deployable.
🔥 Challenge Exercise
Practice the feature-branch workflow end to end: branch off main, make focused commits, push, open a PR, merge, and delete the branch. Explain why keeping main always releasable and isolating work in short-lived branches reduces risk.
📋 Summary
- The three non-negotiable rules: main is always deployable, no direct commits to main, PRs require review + CI.
- Workflow: pull main → create branch → work → push → open PR → review → merge → delete branch.
- Use git push -u origin branch-name on first push to set upstream tracking.
- Branch naming: use prefixes like
feature/,bugfix/,hotfix/,chore/,docs/. - Good PRs: clear title, description, linked issue, small scope, passing CI.
- Trunk-based development: same idea but with very short-lived branches + feature flags.
- Feature Branch Workflow is the right default for most teams in 2026.
Interview Questions
- What is the feature-branch workflow?
- Why isolate work in branches?
- What state should main always be in?
- What is the role of Pull Requests in this workflow?
- Why delete branches after merging?
Related Topics
FAQ
Squash merge: all commits on the feature branch are squashed into one clean commit on main. Best for keeping main history linear and readable — especially when individual commits on the branch are messy WIP commits. Merge commit: preserves the full branch history with a merge commit. Useful when commits are well-crafted and you want to keep the context. Rebase: replays branch commits on top of main with no merge commit — cleanest history but rewrites commit hashes. Most teams default to squash merge for PRs, using the PR title as the commit message.
Two options: merge (git merge origin/main) — adds a merge commit to your branch preserving its history; or rebase (git rebase origin/main) — replays your commits on top of the latest main, resulting in a linear history. Rebase is generally preferred for feature branches to keep history clean, but it rewrites commit hashes which requires a force-push if you've already pushed the branch. For solo branches (only you), rebasing is usually the better choice.
Long-lived branches are a sign that the feature is too large. Consider breaking it into smaller pieces (each merged via a separate PR). If the feature must be long-lived, rebase onto main frequently (daily) to catch conflicts early while they're still small. Some teams use feature flags to merge incomplete features: the code is in main but hidden behind a flag, and the flag is enabled when the feature is done.
A draft PR on GitHub signals "I'm still working on this, not ready for review yet." It's useful for: getting early feedback on your approach, running CI on a work-in-progress, making your work visible to the team without triggering a review request. Convert the draft to a regular PR when it's ready for review by clicking "Ready for review". Draft PRs are a great habit — they increase team visibility and enable collaboration earlier in the development process.

