Git Branching Strategy for Remote Small Teams: A Practical Guide
A complete guide to implementing an effective Git workflow for small remote teams - branch protection, naming conventions, commit standards, and CI/CD integration.
Ever had someone push broken code to production at 5pm on a Friday? Yeah, me too. Or watched two developers spend an entire morning untangling a merge conflict that should’ve been caught days earlier? Fun times.
Here’s the thing - most Git workflow guides are written for massive engineering teams. But if you’re running a small remote team (2-10 developers), you don’t need Facebook’s branching strategy. You need something that actually works without the overhead.
This is what we’ve learned after years of trial and error with small distributed teams. Real conventions that prevent disasters without drowning you in process.
⏱️ Reading time: 15-20 minutes
Why Bother With Git Strategy?
When I first started working with remote teams, we had zero structure. People pushed straight to main, merge conflicts were a weekly disaster, and nobody knew which branch was actually deployed to staging. Sound familiar?
Here’s what a simple Git workflow fixes:
- No more Friday 5pm disasters - Clear rules mean fewer “oh crap” moments
- Code actually gets reviewed - Branch protection makes it impossible to skip
- Staging doesn’t break every other day - Separate environments are a lifesaver
- New devs aren’t confused - They know exactly where to push their code on day one
- Async teamwork works - Remote teams across timezones don’t step on each other
A good Git strategy isn’t about following rules perfectly - it’s about making it harder to accidentally break production while keeping deployment fast.
Our Recommended Branching Model
We use a simplified Git Flow tailored for small teams, with four branch types:
%%{init: { 'theme': 'base', 'themeVariables': { 'git0': '#7B42BC', 'git1': '#2496ED', 'git2': '#00AA00', 'git3': '#FF9900', 'gitBranchLabel0': '#ffffff', 'gitBranchLabel1': '#ffffff', 'gitBranchLabel2': '#ffffff', 'gitBranchLabel3': '#ffffff', 'commitLabelColor': '#ffffff', 'commitLabelBackground': '#333333' }}}%%
gitGraph
commit id: "Initial commit"
branch develop
checkout develop
commit id: "Setup dev environment"
branch feature/user-auth
checkout feature/user-auth
commit id: "Add login form"
commit id: "Add authentication"
checkout develop
merge feature/user-auth
commit id: "v1.1.0-dev" tag: "v1.1.0-dev"
checkout main
branch staging
checkout staging
merge develop tag: "v1.1.0-rc1"
checkout main
merge staging tag: "v1.1.0"
checkout develop
branch feature/dashboard
checkout feature/dashboard
commit id: "Create dashboard"
checkout develop
merge feature/dashboard
checkout staging
merge develop tag: "v1.2.0-rc1"
checkout main
merge staging tag: "v1.2.0"
How This Actually Works: Real Example
Let’s say Sarah needs to build user authentication, and Mike’s working on a dashboard. Two features, two developers, no drama. Here’s how it plays out.
Phase 1: Project Setup (Yes, boring but important)
# Someone (usually whoever starts the project) does this once:
git init
git commit -m "chore: initial commit"
# Create develop branch - this is where features get integrated
git checkout -b develop
git commit -m "chore: setup dev environment"
git push -u origin developWhat just happened? We’ve got a main branch (that’s production) and a develop branch (where stuff gets tested before going live). Simple.
Phase 2: Dev-A Works on User Authentication
Dev-A’s workflow:
# Dev-A creates feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/user-auth
# Dev-A implements login form
git add src/auth/LoginForm.tsx
git commit -m "feat(auth): add login form component"
# Dev-A implements authentication logic
git add src/auth/authentication.ts
git commit -m "feat(auth): add JWT authentication logic"
# Dev-A pushes feature branch
git push -u origin feature/user-authWhat happened: Dev-A creates isolated commits on feature/user-auth without affecting others.
Phase 3: Dev-A Creates Pull Request
Dev-A creates PR:
# Dev-A ensures branch is up to date
git checkout feature/user-auth
git pull origin develop # Get latest changes
git push origin feature/user-auth
# Create Pull Request via GitLab/GitHub UI or CLI
gh pr create \
--base develop \
--head feature/user-auth \
--title "feat: Add user authentication system" \
--body "## Changes
- Add login form component
- Implement JWT authentication
- Add token refresh mechanism
## Testing
- [x] Unit tests pass
- [x] Manual testing completed
- [x] No breaking changes
Closes #123"PR Review Process:
- Dev-B reviews the code
- Dev-B leaves comments: “Please add error handling for token expiration”
- Dev-A pushes fixes to the same branch
- Dev-B approves the PR
Merge to develop:
# After PR approval, Dev-A or team lead merges
git checkout develop
git pull origin develop
git merge --no-ff feature/user-auth
git tag -a v1.1.0-dev -m "Dev release: User authentication"
git push origin develop --follow-tags
# Clean up feature branch
git branch -d feature/user-auth
git push origin --delete feature/user-authWhat happened:
- PR ensured code review before merge
- User authentication integrated in
developand tagged asv1.1.0-dev - Feature branch deleted (clean repository)
Phase 4: Deploy to Staging for Testing
Team lead creates PR: develop → staging:
# Team lead creates staging release PR
gh pr create \
--base staging \
--head develop \
--title "release: v1.1.0-rc1 - User authentication" \
--body "## Release Candidate v1.1.0-rc1
### Features
- User authentication system (PR #45)
### QA Checklist
- [ ] Login flow works correctly
- [ ] Token refresh working
- [ ] Error handling verified
- [ ] Performance acceptable
- [ ] Security scan passed
### Deployment
- Target: Staging environment
- Expected deployment time: 5 minutes"Merge to staging:
# After PR approval from team lead
git checkout staging
git pull origin staging
git merge --no-ff develop
git tag -a v1.1.0-rc1 -m "Release Candidate: User authentication"
git push origin staging --follow-tagsWhat happened:
- PR documents what’s being released to staging
- Staging branch created from
main(mirrors production) developmerged tostagingwith RC (Release Candidate) tag- QA team tests on staging environment
- CI/CD automatically deploys to staging server
Phase 5: Deploy to Production
After successful testing on staging, team lead creates production PR:
# Team lead creates production release PR
gh pr create \
--base main \
--head staging \
--title "release: v1.1.0 - User authentication system" \
--body "## Production Release v1.1.0
### What's New
- User authentication with JWT tokens
- Login/logout functionality
- Token refresh mechanism
### QA Status
- All tests passed on staging
- Manual QA completed
- Security scan: No issues
- Performance: Within acceptable limits
### Rollback Plan
If issues occur, rollback to v1.0.0:
\`\`\`bash
git checkout main
git reset --hard v1.0.0
git push --force origin main
\`\`\`"Merge to production:
# After all approvals (requires 2 reviewers for main)
git checkout main
git merge --no-ff staging
git tag -a v1.1.0 -m "Release v1.1.0: User authentication system"
git push origin main --follow-tagsWhat happened:
- PR requires 2 approvals (protected branch rule)
- All stakeholders signed off
- User authentication is now live in production with version
v1.1.0 - Rollback plan documented in PR
Phase 6: Dev-B Works on Dashboard (Parallel Development)
Meanwhile, Dev-B starts working (even before v1.1.0 goes to production):
# Dev-B creates feature branch from latest develop
git checkout develop
git pull origin develop # Gets v1.1.0-dev code
git checkout -b feature/dashboard
# Dev-B implements dashboard
git add src/dashboard/
git commit -m "feat(dashboard): create user dashboard with metrics"
# Dev-B pushes work
git push -u origin feature/dashboardWhat happened: Dev-B works independently on feature/dashboard while Dev-A’s code is being tested.
Phase 7: Dev-B Creates Pull Request for Dashboard
Dev-B creates PR:
# Dev-B ensures feature is ready
git checkout feature/dashboard
git pull origin develop # Sync with latest develop
git push origin feature/dashboard
# Create Pull Request
gh pr create \
--base develop \
--head feature/dashboard \
--title "feat: Add user dashboard with metrics" \
--body "## Changes
- Create dashboard layout component
- Add real-time metrics display
- Implement data fetching hooks
## Screenshots

## Testing
- [x] Unit tests pass
- [x] Integration tests pass
- [x] Tested on Chrome, Firefox, Safari
## Dependencies
- Requires authentication feature (already merged)
Closes #124"PR Review Process:
- Dev-A reviews the code
- Dev-A comments: “Great work! Just one suggestion: add loading states”
- Dev-B pushes update
- Dev-A approves
Merge to develop:
# After PR approval
git checkout develop
git pull origin develop
git merge --no-ff feature/dashboard
# No tag needed this time (optional for dev releases)
git push origin develop
# Clean up
git branch -d feature/dashboard
git push origin --delete feature/dashboardWhat happened:
- Dev-A and Dev-B collaborated via PR review
- Dashboard feature integrated into
develop - Code quality maintained through peer review
Phase 8: Deploy Dashboard to Staging
Team lead creates staging PR:
# Create PR: develop → staging
gh pr create \
--base staging \
--head develop \
--title "release: v1.2.0-rc1 - User dashboard" \
--body "## Release Candidate v1.2.0-rc1
### New Features
- User dashboard with real-time metrics (PR #46)
### Included in this release
- User authentication (v1.1.0)
- Dashboard feature (v1.2.0)
### QA Checklist
- [ ] Dashboard displays correctly
- [ ] Metrics update in real-time
- [ ] Loading states work
- [ ] Compatible with existing auth
### Deployment
- Target: Staging environment"Merge to staging:
# After PR approval
git checkout staging
git pull origin staging
git merge --no-ff develop
git tag -a v1.2.0-rc1 -m "Release Candidate: Dashboard feature"
git push origin staging --follow-tagsWhat happened:
- PR documents the dashboard release
- Staging now has both user auth (v1.1.0) and dashboard features for testing
- QA team validates on staging
Phase 9: Deploy Dashboard to Production
After QA approval, team lead creates production PR:
# Create production release PR
gh pr create \
--base main \
--head staging \
--title "release: v1.2.0 - User dashboard" \
--body "## Production Release v1.2.0
### What's New
- User dashboard with real-time metrics
- Performance monitoring charts
- Responsive design for mobile/desktop
### QA Status
- All staging tests passed
- Performance: Page load < 2s
- Accessibility: WCAG AA compliant
- Cross-browser tested
### Rollback Plan
If issues occur, rollback to v1.1.0:
\`\`\`bash
git checkout main
git reset --hard v1.1.0
git push --force origin main
\`\`\`
### Deployment Window
- Scheduled: Tuesday 2PM UTC (low traffic period)
- Duration: ~5 minutes
- Monitoring: 1 hour post-deployment"Merge to production:
# After 2 reviewers approve
git checkout main
git merge --no-ff staging
git tag -a v1.2.0 -m "Release v1.2.0: User dashboard"
git push origin main --follow-tagsWhat happened:
- Production PR required 2 approvals
- All stakeholders reviewed and signed off
- Dashboard is now live in production as version
v1.2.0 - Team monitors deployment for 1 hour
Key Takeaways from This Workflow
Parallel Development
- Dev-A and Dev-B worked simultaneously without conflicts
- Feature branches kept work isolated
Quality Gates
- Every feature went through: develop → staging → main
- QA tested on staging before production
Clear History
- Version tags show what’s in each release
- Easy to track what went to production and when
Safe Rollbacks
- If v1.2.0 breaks, rollback to v1.1.0 using git tags
- Staging environment caught issues before production
Team Coordination
- Develop branch integrates all features
- Staging acts as pre-production testing ground
- Main always represents production state
Branch Structure Overview
| Branch | Purpose | Lifetime | Protected | Deploys To |
|---|---|---|---|---|
main | Production-ready code | Permanent | ✅ Yes | Production |
staging | Pre-production testing | Permanent | ✅ Yes | Staging Environment |
develop | Integration branch | Permanent | ✅ Yes | Development Environment |
feature/* | Feature development | Temporary | ❌ No | Preview (optional) |
bugfix/* | Bug fixes | Temporary | ❌ No | - |
hotfix/* | Emergency production fixes | Temporary | ❌ No | - |
Branch Purposes and Rules
1. Main Branch (main)
Purpose: Contains only production-ready, tested, and approved code.
Rules:
- Always deployable to production
- Protected - no direct commits allowed
- Only accepts merges from
stagingbranch - Requires code review approval
- All CI/CD tests must pass
- Tagged with semantic versions (v1.0.0, v1.1.0, etc.)
Who can merge: Team lead or designated release manager
Deployment: Automatically deploys to production after merge (with approval)
# ❌ NEVER do this
git checkout main
git commit -m "Quick fix"
git push
# ALWAYS do this
git checkout -b hotfix/critical-bug
# Make changes
git push origin hotfix/critical-bug
# Create pull request to staging → main2. Staging Branch (staging)
Purpose: Pre-production testing environment that mirrors production.
Rules:
- Protected - no direct commits allowed
- Only accepts merges from
developorhotfix/*branches - Requires 1 code review approval
- All automated tests must pass
- Used for QA and client demos
- Tagged with release candidates (v1.1.0-rc1, v1.1.0-rc2)
Who can merge: Any developer with approval
Deployment: Automatically deploys to staging environment
Testing checklist before promoting to main:
- All features work as expected
- No breaking changes
- Performance is acceptable
- Security scan passed
- Client/stakeholder approval (if needed)
3. Develop Branch (develop)
Purpose: Main integration branch where features come together.
Rules:
- Protected - no direct commits allowed
- Accepts merges from
feature/*andbugfix/*branches - Requires code review (can be less strict than staging)
- CI/CD tests should pass
- Most active branch for development
Who can merge: Any developer after review
Deployment: Automatically deploys to development environment
# Feature is complete and tested
git checkout develop
git pull origin develop
git merge --no-ff feature/user-authentication
git push origin develop4. Feature Branches (feature/*)
Purpose: Develop new features in isolation.
Rules:
- Branch from
develop - Merge back to
developwhen complete - Delete after merging
- Keep focused on single feature
- Regularly sync with
developto avoid conflicts
Lifetime: Created when starting feature → Deleted after merge
Naming convention: feature/short-descriptive-name
# Create feature branch
git checkout develop
git pull origin develop
git checkout -b feature/user-dashboard
# Work on feature
git add .
git commit -m "feat: add user dashboard layout"
git push origin feature/user-dashboard
# Keep up to date with develop
git checkout develop
git pull origin develop
git checkout feature/user-dashboard
git merge develop5. Bugfix Branches (bugfix/*)
Purpose: Fix bugs found in development or staging.
Rules:
- Branch from
develop - Merge back to
develop - Delete after merging
Naming convention: bugfix/issue-description
6. Hotfix Branches (hotfix/*)
Purpose: Emergency fixes for production issues.
Rules:
- Branch from
main - Merge to both
mainANDdevelop - Highest priority
- Minimal changes only
Naming convention: hotfix/critical-issue-description
Workflow:
# Production is broken!
git checkout main
git pull origin main
git checkout -b hotfix/payment-gateway-crash
# Fix the issue
git add .
git commit -m "fix: resolve payment gateway timeout"
git push origin hotfix/payment-gateway-crash
# Create pull requests:
# 1. hotfix/payment-gateway-crash → staging → main
# 2. hotfix/payment-gateway-crash → developBranch Protection Rules
Here’s what I actually configure in GitHub/GitLab - not every checkbox, just the ones that prevent disasters:
Protect Your Main Branch (Non-negotiable)
This is production. Lock it down.
- ✅ 2 approvals required - No solo cowboys merging to prod
- ✅ CI must pass - Build, tests, and security scans
- ❌ No force pushes - Seriously, just don’t
- 🔒 Only team leads can merge - Someone needs to be responsible
What I skip: Signed commits (nice in theory, annoying in practice for small teams), conversation resolution (we’re adults), branch deletion protection (not needed if you’re not reckless).
If you forgot to create a feature branch and committed directly to main (we’ve all done it), check out our guide on how to fix accidental commits to main. It walks you through moving your commits to a feature branch safely without losing any work.
Staging Branch Protection
Lighter than main, but still protected:
- ✅ 1 approval required - Quick review before testing
- ✅ CI must pass - Build and tests (skip the heavy scans)
- ❌ No force pushes - Keep history clean
Develop Branch Protection
Basic guardrails:
- ✅ 1 approval - Catch obvious issues
- ✅ Build + lint must pass - Don’t break the integration branch
- ❌ No force pushes - Play nice with others
You can add more protections later, but start with these and you’ll prevent 90% of problems.
Naming Conventions
Branch Naming
Follow this pattern: <type>/<short-description>
Types:
feature/- New featuresbugfix/- Bug fixeshotfix/- Production hotfixesrefactor/- Code refactoringdocs/- Documentation updatestest/- Adding testschore/- Maintenance tasks
Examples:
| ✅ Good Branch Names | ❌ Bad Branch Names | Why? |
|---|---|---|
feature/user-authentication | fix-stuff | Vague, no context on what’s being fixed |
feature/payment-integration | johns-branch | Who’s John? What’s he working on? |
bugfix/login-redirect-loop | temp | ”Temporary” branches that live forever |
hotfix/database-connection-timeout | new-feature | Which feature? There are 20 features |
refactor/api-error-handling | branch-1 | Numbers mean nothing 2 weeks later |
docs/api-documentation | wip | Everything is “work in progress” |
feature/123-user-dashboard | test | Testing what? Too generic |
Branch naming rules (the non-negotiables):
- Kebab-case only -
feature/user-auth, notfeature/userAuthorfeature/user_auth - 2-4 words max - Be descriptive but concise (
feature/add-user-profile-pageis pushing it) - Present tense -
feature/add-loginnotfeature/added-loginorfeature/adding-login - Include issue numbers -
feature/123-user-dashboardlinks to issue #123 - No special characters - Only
/and-allowed (no underscores, spaces, or weird symbols)
Commit Messages (Keep It Simple)
You just follow this basic pattern:
<type>: what you actually didThe types I use 90% of the time:
feat:- New feature (e.g., “feat: add login page”)fix:- Bug fix (e.g., “fix: prevent crash on empty input”)chore:- Boring maintenance (e.g., “chore: update dependencies”)
That’s it. Yes, there are like 10 more types (docs, style, refactor, perf, test, ci, build…), but honestly? Start with these three. You can get fancy later.
Good commit messages:
feat: add JWT token refresh mechanism
fix: resolve timeout in user API endpoint
chore: update axios to v1.6.0Bad commit messages (we’ve all done these):
fixed bug
updated files
WIP
asdfgh
more stuff
final version
final version 2 # <- guiltySee the difference? One tells you nothing, the other tells you exactly what changed.
Optional scope - If your project is big enough:
feat(auth): add JWT refresh
fix(api): resolve user endpoint timeoutBut for small teams? The simple version works fine.
Commit message template:
Create .gitmessage in your repository:
# <type>(<scope>): <subject>
# |<---- Using a Maximum Of 50 Characters ---->|
# Explain why this change is being made
# |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->|
# Provide links or keys to any relevant tickets, articles or other resources
# Example: Closes #23
# --- COMMIT END ---
# Type can be
# feat (new feature)
# fix (bug fix)
# refactor (refactoring production code)
# style (formatting, missing semi colons, etc; no code change)
# docs (changes to documentation)
# test (adding or refactoring tests; no production code change)
# chore (updating grunt tasks etc; no production code change)
# perf (performance improvements)
# ci (CI/CD changes)
# build (build system changes)
# --------------------
# Remember to
# Capitalize the subject line
# Use the imperative mood in the subject line
# Do not end the subject line with a period
# Separate subject from body with a blank line
# Use the body to explain what and why vs. how
# Can use multiple lines with "-" for bullet points in body
# --------------------Configure git to use this template:
git config --global commit.template .gitmessageTag Naming Convention
Use Semantic Versioning (semver.org): vMAJOR.MINOR.PATCH
Format: vX.Y.Z
- MAJOR (X): Breaking changes
- MINOR (Y): New features (backward compatible)
- PATCH (Z): Bug fixes (backward compatible)
Examples:
# Production releases (on main)
v1.0.0 # Initial release
v1.1.0 # Added new feature
v1.1.1 # Bug fix
v2.0.0 # Breaking changes
# Release candidates (on staging)
v1.1.0-rc1 # First release candidate
v1.1.0-rc2 # Second release candidate
# Pre-releases (on develop)
v1.1.0-alpha
v1.1.0-betaCreating tags:
# Annotated tag (recommended)
git tag -a v1.2.0 -m "Release version 1.2.0: Add user dashboard and notifications"
# Push tag to remote
git push origin v1.2.0
# Push all tags
git push origin --tagsComplete Workflow Examples
Scenario 1: Developing a New Feature
# 1. Start from latest develop
git checkout develop
git pull origin develop
# 2. Create feature branch
git checkout -b feature/notification-system
# 3. Work on feature (make multiple commits)
git add src/notifications/
git commit -m "feat(notifications): add email notification service"
git add src/notifications/
git commit -m "feat(notifications): add push notification support"
git add tests/notifications/
git commit -m "test(notifications): add notification service tests"
# 4. Keep branch updated (if develop has moved ahead)
git checkout develop
git pull origin develop
git checkout feature/notification-system
git merge develop
# 5. Push feature branch
git push origin feature/notification-system
# 6. Create Pull Request: feature/notification-system → develop
# - Add description of changes
# - Request reviewer
# - Link related issues
# 7. After approval and merge, delete branch
git checkout develop
git pull origin develop
git branch -d feature/notification-system
git push origin --delete feature/notification-systemScenario 2: Releasing to Production
# 1. Merge develop to staging
git checkout staging
git pull origin staging
git merge develop
git push origin staging
# Tag release candidate
git tag -a v1.3.0-rc1 -m "Release candidate for v1.3.0"
git push origin v1.3.0-rc1
# 2. Test on staging environment
# - Run manual tests
# - Check all features
# - Get stakeholder approval
# 3. If tests pass, merge staging to main
git checkout main
git pull origin main
git merge staging
git push origin main
# 4. Tag production release
git tag -a v1.3.0 -m "Release v1.3.0: Add notification system and user dashboard"
git push origin v1.3.0
# 5. Ensure develop is synced
git checkout develop
git merge main
git push origin developScenario 3: Emergency Production Hotfix
# 1. Branch from main
git checkout main
git pull origin main
git checkout -b hotfix/payment-api-timeout
# 2. Fix the issue
git add src/payment/
git commit -m "fix(payment): increase API timeout to 30s"
# 3. Test locally
npm test
# 4. Push and create PR to staging first
git push origin hotfix/payment-api-timeout
# Create PR: hotfix/payment-api-timeout → staging
# 5. After staging tests pass, merge to main
# Create PR: staging → main
# 6. Merge hotfix to develop
git checkout develop
git pull origin develop
git merge hotfix/payment-api-timeout
git push origin develop
# 7. Tag hotfix release
git checkout main
git tag -a v1.3.1 -m "Hotfix v1.3.1: Fix payment API timeout"
git push origin v1.3.1
# 8. Delete hotfix branch
git branch -d hotfix/payment-api-timeout
git push origin --delete hotfix/payment-api-timeoutScenario 4: Handling Merge Conflicts
# You're on feature branch and want to merge develop
git checkout feature/user-profile
git merge develop
# Conflict detected!
# Auto-merging src/components/Profile.tsx
# CONFLICT (content): Merge conflict in src/components/Profile.tsx
# 1. Check conflicted files
git status
# 2. Open files and resolve conflicts
# Look for conflict markers:
# <<<<<<< HEAD
# Your changes
# =======
# Changes from develop
# >>>>>>> develop
# 3. After resolving, mark as resolved
git add src/components/Profile.tsx
# 4. Complete the merge
git commit -m "merge: resolve conflicts with develop"
# 5. Push updated branch
git push origin feature/user-profilePull Request Guidelines
Creating Pull Requests
PR Title Format:
Your PR title is what shows up in changelogs, Git history, and Slack notifications. Make it count.
Format:
<type>: <what you actually did>✅ Good PR titles (clear, actionable, tells you what changed):
feat: Add user notification system
fix: Resolve login redirect loop on expired tokens
docs: Update API authentication guide
refactor: Optimize database query performance in user service
hotfix: Patch XSS vulnerability in comment form
feat(auth): Add JWT refresh token rotation❌ Bad PR titles (vague, doesn’t tell you anything useful):
Update notifications # Update how? What changed?
Fixed bug # Which bug? Where?
Docs # What docs? Too vague
Code cleanup # What code? Cleanup how?
Security fix # Need specifics for hotfixes
Add feature # Which feature?Title length: Aim for 50-72 characters. If you can’t fit it, your PR is probably too big.
PR Description Template:
## Description
Brief description of changes made
## Type of Change
- [ ] New feature
- [ ] Bug fix
- [ ] Breaking change
- [ ] Documentation update
- [ ] Refactoring
- [ ] Performance improvement
## Related Issues
Closes #123
Related to #456
## Changes Made
- Added notification email service
- Implemented push notification support
- Created notification preferences UI
- Added unit tests for notification service
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
- [ ] Tested on Chrome, Firefox, Safari
## Screenshots (if applicable)
[Add screenshots here]
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings introduced
- [ ] Tests added/updated
- [ ] All tests passingCode Review Checklist
For Reviewers:
- Code follows team conventions
- No unnecessary complexity
- Proper error handling
- Security considerations addressed
- Performance implications considered
- Tests are adequate
- Documentation is updated
- No debugging code left behind
- Commit messages follow convention
Merging Strategies
We use different strategies for different branches:
# For feature → develop: Squash and merge (clean history)
git checkout develop
git merge --squash feature/user-auth
git commit -m "feat: add user authentication system"
# For develop → staging: Merge commit (preserve feature commits)
git checkout staging
git merge --no-ff develop
# For staging → main: Merge commit (preserve all history)
git checkout main
git merge --no-ff stagingWhy different strategies?
- Squash merge: Keeps
develophistory clean, one commit per feature - Merge commit: Preserves detailed history for staging and production
Automating Quality Checks with Git Hooks
Git hooks are your first line of defense against bad code reaching your repository. They automatically validate code quality, enforce commit standards, and catch mistakes before they embarrass you in code review or break CI.
Automating Quality Checks with Git Hooks
Git hooks are your first line of defense against bad code reaching your repository. They automatically validate code quality, enforce commit standards, and catch mistakes before they embarrass you in code review or break CI.
What Git hooks can prevent:
- Linting errors and failing tests
- Invalid commit message formats
- Hardcoded secrets or API keys
- Direct commits to protected branches
Instead of repeating the full setup here, we’ve created a dedicated guide that covers everything you need to know about Git hooks - from basic pre-commit checks to advanced patterns like auto-formatting and secret detection.
For detailed instructions on setting up Git hooks with Husky, integrating with CI/CD, and common hook patterns, see our dedicated guides:
Git Hooks for Automation: Catch Mistakes Before They Embarrass You → - Theory and patterns
Implementing Git Hooks with Husky: A Real-World Example → - Practical setup guide
The guides include:
- Pre-commit, commit-msg, and pre-push hook examples
- Husky setup for team-wide hook sharing
- Real-world implementation in an Astro project
- Common patterns (prevent commits to main, check for secrets)
- Troubleshooting and CI/CD integration
Setting up hooks takes 5 minutes and saves hours of debugging. Highly recommended for any team workflow.
For complete CI/CD integration examples (including multi-environment deployments), see the Git Hooks automation guide.
Team Workflow Best Practices
Daily Development Flow
Morning:
# Start your day by syncing
git checkout develop
git pull origin developDuring Development:
# Commit often with good messages
git add .
git commit -m "feat(feature): add specific functionality"
# Push regularly to backup and share progress
git push origin feature/your-featureBefore Lunch/End of Day:
# Sync with develop to avoid conflicts later
git checkout develop
git pull origin develop
git checkout feature/your-feature
git merge developCommunication Guidelines
When to notify team:
- Before merging to
develop(affects everyone) - Before merging to
staging(for QA/testing) - Before merging to
main(production release) - When deploying hotfixes
- When encountering blocking issues
Communication channels:
- Slack/Teams: Quick updates, PR reviews needed
- Daily standups: Current branch, blockers
- PR comments: Code-specific discussions
- Documentation: Architectural decisions
Troubleshooting Common Issues
Issue 1: “I committed to wrong branch”
# You're on develop but should be on feature branch
# 1. Create feature branch from current state
git checkout -b feature/my-feature
# 2. Reset develop to remote state
git checkout develop
git reset --hard origin/develop
# 3. Your commits are now on feature branch
git checkout feature/my-featureIssue 2: “I need to undo last commit”
# Undo commit but keep changes
git reset --soft HEAD~1
# Undo commit and discard changes
git reset --hard HEAD~1
# Undo commit that was already pushed (creates new commit)
git revert HEADIssue 3: “My branch is behind main”
# Update your branch with latest main
git checkout feature/my-feature
git fetch origin
git merge origin/main
# Or use rebase for cleaner history
git rebase origin/mainIssue 4: “Accidentally pushed to protected branch”
# If push was rejected - good! Branch protection worked
# If push succeeded - contact admin immediately
# Admin can:
# 1. Revert the commit
git revert <commit-hash>
git push origin main
# 2. Or reset branch (if no one pulled yet)
git reset --hard <commit-before-mistake>
git push --force origin main # Only admin can do thisMetrics and Monitoring
Track these metrics to improve your workflow:
Git Health Metrics
- Average PR time to merge: < 24 hours
- Branch lifetime: Feature branches < 3 days
- Merge conflicts: < 10% of merges
- Failed builds: < 5% of pushes
- Hotfix frequency: < 1 per week
Tools for Monitoring
# Check branch age
git for-each-ref --sort=committerdate refs/heads/ \
--format='%(committerdate:short) %(refname:short)'
# Count commits per author
git shortlog -sn --all
# Check merge frequency
git log --merges --oneline | wc -lOnboarding New Team Members
Day 1 Checklist
- Clone repository
- Install git hooks
- Read this guide
- Configure git username and email
- Set up commit message template
- Add SSH key to Git host
- Join team chat channels
- Review recent PRs
Practice Exercise
Give new members a safe task:
# 1. Create practice branch
git checkout -b feature/onboarding-<name>
# 2. Make a small change
# Edit README.md - add your name to contributors
# 3. Commit with proper format
git commit -m "docs(readme): add <name> to contributors"
# 4. Push and create PR
git push origin feature/onboarding-<name>
# 5. Get it reviewed and mergedSummary Cheat Sheet
Quick Commands
# Start new feature
git checkout develop && git pull && git checkout -b feature/name
# Update feature with develop
git checkout develop && git pull && git checkout - && git merge develop
# Finish feature
git push origin feature/name # Then create PR
# Quick status
git status && git log --oneline -5
# Clean up merged branches
git branch --merged | grep -v "\*" | xargs -n 1 git branch -dBranch Lifecycle
Here’s how branches flow through your environments from creation to deletion:
flowchart TD
A[Create Feature Branch] --> B[Develop & Commit]
B --> C[Open PR to develop]
C --> D{Code Review}
D -->|Changes Requested| B
D -->|Approved| E[Merge to develop]
E --> F[Auto-deploy to DEV env]
F --> G[Test in DEV]
G --> H{Ready for Staging?}
H -->|Not Yet| B
H -->|Yes| I[Merge to staging]
I --> J[Auto-deploy to STAGING]
J --> K[QA Testing]
K --> L{Production Ready?}
L -->|Issues Found| B
L -->|Approved| M[Merge to main]
M --> N[Deploy to PRODUCTION]
N --> O[Delete Feature Branch]
style A fill:#e1f5ff,stroke:#0066cc,stroke-width:2px
style E fill:#fff4e1,stroke:#ff9900,stroke-width:2px
style I fill:#ffeaa7,stroke:#fdcb6e,stroke-width:2px
style M fill:#d4f4dd,stroke:#00b894,stroke-width:2px
style O fill:#ff7979,stroke:#d63031,stroke-width:2px
style D fill:#ffd700,stroke:#ff8800,stroke-width:2px
style H fill:#ffd700,stroke:#ff8800,stroke-width:2px
style L fill:#ffd700,stroke:#ff8800,stroke-width:2px
Branch lifespan by type:
| Branch Type | Created When | Deleted When | Typical Lifespan |
|---|---|---|---|
feature/* | Starting new work | After merged to develop | 1-7 days |
bugfix/* | Fixing non-critical bug | After merged to develop | 1-3 days |
hotfix/* | Production emergency | After merged to main | 2-4 hours |
develop | Project start | Never (permanent) | Entire project |
staging | Project start | Never (permanent) | Entire project |
main | Project start | Never (permanent) | Entire project |
Key points:
- Feature branches are temporary - delete them after merging
- Long-lived feature branches (>1 week) = code review hell
- If your feature branch is older than 2 weeks, you’re doing something wrong (break it down!)
Protection Summary
| Branch | Protection | Required Approvals | Auto-Deploy |
|---|---|---|---|
main | Maximum | 2 reviewers | Manual only |
staging | High | 1 reviewer | Auto to staging |
develop | Medium | 1 reviewer | Auto to dev |
feature/* | None | - | Optional preview |
The Bottom Line
Look, you made it through 1500+ lines of Git workflow documentation. Here’s what actually matters:
This workflow gives you:
- No more Friday 5pm disasters - Branch protection catches mistakes before they hit prod
- Code reviews that actually happen - Not optional when it’s required to merge
- New developers who aren’t lost - They know exactly where to push on day one
- Confidence when deploying - Staging caught the bugs, production is clean
Your team doesn’t need to follow this exactly. Got a team of 3? Skip some of the ceremony. Growing to 10? Add more guardrails. The point isn’t perfection - it’s having some structure so nobody accidentally nukes production.
Start with protecting your main branch this week. Add the rest as you go. Your future self (and your team) will thank you when you’re NOT debugging production at midnight.
Next Steps: Implement This Today
Ready to implement this strategy? Here’s your 3-week action plan:
Day 1 - Set Up Branch Protection (30 minutes)
- Protect
mainbranch with 2 required approvals - Protect
staginganddevelopwith 1 required approval - Enable status checks (CI/CD must pass)
Day 2 - Create Documentation (1 hour)
- Add
GIT_WORKFLOW.mdto your repository (use template below) - Share this guide with your team
- Schedule a 30-minute team walkthrough
Day 3 - Install Git Hooks (1 hour)
- Set up Husky and commitlint
- Configure pre-commit linting checks
- Test hooks with a dummy commit
- Each team member practices with a feature branch
- Create at least one PR per person
- Review and refine the workflow based on feedback
- Address questions and concerns in team standup
- Move all active work to the new workflow
- Monitor merge conflicts (should decrease)
- Measure PR review times
- Celebrate wins and learn from challenges
Have questions about implementing this workflow? Check out our related guides or reach out in the comments below.
Additional Resources
- Conventional Commits
- Semantic Versioning
- Git Flow Original Paper
- GitHub Flow
- GitLab Flow
- Atlassian Git Tutorials
Appendix: Team Agreement Template
Create a GIT_WORKFLOW.md file in your repository:
# Our Git Workflow Agreement
## Branches We Use
- main (production)
- staging (pre-production)
- develop (integration)
- feature/\* (features)
- hotfix/\* (emergency fixes)
## Rules We Follow
1. Never commit directly to main, staging, or develop
2. Always create PR for code review
3. Delete branches after merging
4. Write meaningful commit messages
5. Keep feature branches short-lived (<3 days)
6. Sync with develop daily
7. Test before pushing
8. Tag all production releases
## Code Review Standards
- Response time: < 24 hours
- Be constructive and specific
- Approve only if you'd deploy it
- Block if security/performance issues
## Emergency Protocol
1. Hotfix branches from main
2. Notify team in #urgent channel
3. Fast-track review
4. Deploy immediately after testing
5. Create incident report
Signed by team: [Names and dates]Need help implementing this workflow? Start small - protect your main branch first, then gradually add the other protections and conventions as your team grows comfortable with the process.
Share this post
Found this helpful? Share it with your network!
