A branching strategy is your team’s agreement on how work flows through Git: where features are developed, how they’re reviewed, and what gets deployed. The right choice depends on how often you deploy, and how many versions you maintain. For most web apps on a VPS, simpler is better.
The main models
| Model | Branches | Best for |
|---|---|---|
| Trunk-based development | main + very short-lived branches (hours to a day) |
Teams with strong CI, continuous deployment |
| GitHub Flow | main + feature branches merged via pull requests |
Most web apps and SaaS |
| GitFlow | main, develop, feature/*, release/*, hotfix/* |
Versioned software with scheduled releases |
| Release branches | main + release/1.x, release/2.x |
Maintaining several supported versions |
GitHub Flow (a good default)
- Branch from
main:git switch -c feature/invoice-export. - Commit, push, open a pull request.
- CI runs tests. A teammate reviews.
- Merge to
main(squash or merge commit). maindeploys to production (automatically, or with a manual approval).
git switch main && git pull
git switch -c fix/login-redirect
# … work …
git push -u origin fix/login-redirect
Rule: main is always deployable. Release versions with tags. See Git tags and releases.
Trunk-based development
Everyone integrates into main at least daily. Unfinished features hide behind feature flags rather than living in long-running branches. It minimises merge conflicts, and suits teams that deploy many times a day. See feature flags.
GitFlow
developcollects finished features.mainonly receives releases.release/x.ybranches stabilise a version.hotfix/*patches production.
It adds ceremony and merge overhead. It’s useful for software shipped to customers in versions (desktop apps, libraries, on-premises products), and usually unnecessary for a website or SaaS deployed continuously.
Environments: branches or tags?
Avoid branch-per-environment setups (dev, staging, prod branches that drift apart). Prefer:
- one main branch;
- deploy the same commit or image tag to staging, then production;
- promote by tag or approval, not by merging between environment branches.
See deployment strategies and Docker image tags best practices.
Branch protection
On GitHub, GitLab or Gitea, protect main:
- require pull requests and at least one review;
- require CI status checks to pass;
- disallow force pushes and deletions;
- optionally require linear history (squash or rebase merges).
See Gitea and CI/CD pipeline explained.
Naming conventions
feature/short-description
fix/issue-123-login-loop
chore/update-dependencies
release/1.9
hotfix/1.8.4
Short, lowercase, with a type prefix: easy to filter, and easy to automate (for example labels and changelogs).
Merge style
- Squash merge: one clean commit per pull request on
main. Easy to revert. - Merge commit: keeps branch history.
- Rebase: linear history, without merge commits.
See git merge vs rebase.
Quick reference
| Situation | Strategy |
|---|---|
| Web app / SaaS, small team | GitHub Flow |
| Many deploys per day, strong CI | Trunk-based + feature flags |
| Versioned product, scheduled releases | GitFlow or release branches |
| Environments | Same artifact promoted by tags/approvals |
| Always | Protected main, CI required |
Related: Git commands cheat sheet and Git hooks.