Branching strategies, commit conventions, code review, and release workflows for professional teams.
| Strategy | Best For | Branch Lifetime | Release Cadence |
|---|---|---|---|
| Trunk-Based | CI/CD, small teams | Hours | Continuous |
| GitHub Flow | SaaS, web apps | Days | On merge |
| GitFlow | Versioned software, mobile | Weeks | Scheduled |
main ←── short-lived feature branches (< 2 days)
└── release/* (cut when ready, hotfix → cherry-pick back)
main (or merge within 24h)maingit checkout -b feat/user-avatars
# work, commit, push
gh pr create --base main --fill
# review → squash merge → auto-deploy
main ← tagged releases only
develop ← integration branch
├── feature/* → develop
├── release/* → main + develop
└── hotfix/* → main + develop
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
| Type | SemVer Bump | Example |
|---|---|---|
fix | PATCH | fix(auth): handle expired refresh tokens |
feat | MINOR | feat(api): add pagination to /users |
feat! or BREAKING CHANGE: | MAJOR | feat(api)!: remove v1 endpoints |
chore, docs, ci, refactor, test, perf | none | ci: add Node 22 to matrix |
Enforce with commitlint: npx husky add .husky/commit-msg 'npx commitlint --edit $1'
npx husky init
npm i -D lint-staged
// package.json
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.md": ["prettier --write"]
}
# .husky/pre-commit
npx lint-staged
# .husky/commit-msg
npx commitlint --edit $1
TODO without a linked issueSee references/pr-template.md for a reusable PR template.
| Use | When |
|---|---|
| Squash merge | Feature branches → main (clean history) |
| Rebase | Updating feature branch with latest main |
| Merge commit | Release branches, preserving full history |
# Update feature branch (never rebase shared branches)
git fetch origin && git rebase origin/main
# Interactive rebase to clean up before PR
git rebase -i HEAD~5
# Hotfix: fix on main, cherry-pick to release
git checkout main && git cherry-pick <sha>
git checkout release/2.3 && git cherry-pick <sha>
Always cherry-pick forward (oldest branch → newest). Never backport without testing.
# Semantic versioning tags
git tag -a v2.4.0 -m "Release 2.4.0"
git push origin v2.4.0
# Automate with semantic-release or release-please
# Trigger: push to main → analyze commits → bump version → tag → changelog
See references/release-config.json for semantic-release configuration.
# Nx — affected-only CI
npx nx affected --target=test --base=origin/main
# Turborepo
npx turbo run build --filter=...[origin/main]
# CODEOWNERS for per-package review
# .github/CODEOWNERS
/packages/auth/** @auth-team
/packages/api/** @api-team
# OS
.DS_Store
Thumbs.db
# Dependencies
node_modules/
vendor/
# Build output
dist/
.next/
*.tsbuildinfo
# Environment (NEVER commit secrets)
.env
.env.local
.env.*.local
# IDE
.idea/
.vscode/settings.json
Use git check-ignore -v <file> to debug. Use references/gitignore-templates/ for language-specific templates.
# Undo last commit (keep changes)
git reset --soft HEAD~1
# Find commit that introduced a bug
git bisect start && git bisect bad && git bisect good v2.0.0
# Clean up merged branches
git branch --merged main | grep -v main | xargs git branch -d
# Amend without changing message
git commit --amend --no-edit
# Stash with name
git stash push -m "wip: auth refactor"