Git Branching Strategy: A Practical Case

Git Branching Strategy: A Practical Case

· 28 min read
gitlab-for-your-team

Broken code in production on a Friday night. Merge conflicts that should’ve been caught days ago. Familiar?

Most Git workflow guides target massive teams. For 2-10 developers, you need something simpler.

This guide covers conventions that prevent disasters without drowning you in process.

⏱️ Reading time: 15-20 minutes

Why Bother With Git Strategy?

No structure means people push straight to main, merge conflicts pile up, and nobody knows what’s deployed where.

A simple Git workflow fixes that:

  • No Friday disasters - Clear rules, fewer accidents
  • Code gets reviewed - Branch protection enforces it
  • Staging stays stable - Separate environments help
  • New devs onboard fast - They know where to push on day one
  • Async work works - Timezones don’t cause collisions
💡 The Real Goal

A good Git strategy isn’t about following rules perfectly - it’s about making it harder to accidentally break production while keeping deployment fast.

A simplified Git Flow for small teams, with four branch types:

Diagram

How This Actually Works: Real Example

Sarah builds user authentication. Mike works on a dashboard. Two features, two developers, no drama.

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 develop

Now you have main (production) and develop (integration).


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-auth

Dev-A works in isolation on feature/user-auth. Nobody else is affected.


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 comments: “Add error handling for token expiration”
  • Dev-A pushes fixes
  • Dev-B approves

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-auth

Result: auth merged into develop as v1.1.0-dev, feature branch deleted.


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-tags

Result: develop merged to staging with RC tag. CI/CD auto-deploys. QA begins.


Phase 5: Deploy to Production

After staging tests pass, 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-tags

Result: 2 approvals obtained, user auth live as v1.1.0, rollback plan documented.


Phase 6: Dev-B Works on Dashboard (Parallel Development)

Dev-B starts before v1.1.0 reaches 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/dashboard

Dev-B works independently 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

## 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: “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/dashboard

Result: dashboard integrated into develop.


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-tags

Result: staging has both auth and dashboard. QA validates.


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-tags

Result: 2 approvals, dashboard live as v1.2.0, team monitors 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 reached production and when

Safe Rollbacks

  • Roll back to any previous version via git tags
  • Staging catches issues before production

Team Coordination

  • Develop integrates features
  • Staging gates production
  • Main always reflects production

Branch Structure Overview

BranchPurposeLifetimeProtectedDeploys To
mainProduction-ready codePermanent✅ YesProduction
stagingPre-production testingPermanent✅ YesStaging Environment
developIntegration branchPermanent✅ YesDevelopment Environment
feature/*Feature developmentTemporary❌ NoPreview (optional)
bugfix/*Bug fixesTemporary❌ No-
hotfix/*Emergency production fixesTemporary❌ No-

Branch Purposes and Rules

1. Main Branch (main)

Purpose: Production-ready, tested, approved code only.

Rules:

  • Always deployable
  • Protected — no direct commits
  • Only accepts merges from staging
  • 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 release manager

Deployment: Auto-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 → main

2. Staging Branch (staging)

Purpose: Pre-production testing. Mirrors production.

Rules:

  • Protected — no direct commits
  • Only accepts merges from develop or hotfix/*
  • Requires 1 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: Auto-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: Integration branch where features come together.

Rules:

  • Protected — no direct commits
  • Accepts merges from feature/* and bugfix/*
  • Requires code review (lighter than staging)
  • CI/CD tests should pass
  • Most active branch

Who can merge: Any developer after review

Deployment: Auto-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 develop

4. Feature Branches (feature/*)

Purpose: Isolated feature development.

Rules:

  • Branch from develop
  • Merge back to develop when complete
  • Delete after merging
  • One feature per branch
  • Sync with develop regularly

Lifetime: Created at feature start, 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 develop

5. 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 production fixes.

Rules:

  • Branch from main
  • Merge to both main AND develop
  • 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 → develop

Branch Protection Rules

What to configure in GitHub/GitLab — the settings that prevent disasters:

Protect Your Main Branch (Non-negotiable)

Production. Lock it down.

  • 2 approvals required - No solo merges to prod
  • CI must pass - Build, tests, security scans
  • No force pushes - Ever
  • 🔒 Only team leads can merge - Someone owns this

Skip: signed commits, conversation resolution, branch deletion protection. Overhead for small teams.

💡 Accidentally Committed to Main?

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:

  • 1 approval required - Quick review before testing
  • CI must pass - Build and tests (skip 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

These prevent 90% of problems.

Naming Conventions

Branch Naming

Pattern: <type>/<short-description>

Types:

  • feature/ - New features
  • bugfix/ - Bug fixes
  • hotfix/ - Production hotfixes
  • refactor/ - Code refactoring
  • docs/ - Documentation updates
  • test/ - Adding tests
  • chore/ - Maintenance tasks

Examples:

✅ Good Branch Names❌ Bad Branch NamesWhy?
feature/user-authenticationfix-stuffVague, no context
feature/payment-integrationjohns-branchSays nothing about the work
bugfix/login-redirect-looptemp”Temporary” branches live forever
hotfix/database-connection-timeoutnew-featureWhich feature?
refactor/api-error-handlingbranch-1Meaningless in 2 weeks
docs/api-documentationwipEverything is WIP
feature/123-user-dashboardtestTesting what?

Branch naming rules:

  • Kebab-case only - feature/user-auth, not feature/userAuth or feature/user_auth
  • 2-4 words max - Descriptive but concise
  • Present tense - feature/add-login not feature/added-login
  • Include issue numbers - feature/123-user-dashboard links to issue #123
  • No special characters - Only / and -

Commit Messages (Keep It Simple)

Pattern:

<type>: what you actually did

The three types you need:

  • feat: - New feature (e.g., “feat: add login page”)
  • fix: - Bug fix (e.g., “fix: prevent crash on empty input”)
  • chore: - Maintenance (e.g., “chore: update dependencies”)

More types exist (docs, style, refactor, perf, test, ci, build), but start with these three.

Good commit messages:

feat: add JWT token refresh mechanism
fix: resolve timeout in user API endpoint
chore: update axios to v1.6.0

Bad commit messages (we’ve all done these):

fixed bug
updated files
WIP
asdfgh
more stuff
final version
final version 2  # <- guilty

Optional scope for larger projects:

feat(auth): add JWT refresh
fix(api): resolve user endpoint timeout

For small teams, the simple version works.

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 .gitmessage

Tag 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-beta

Creating 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 --tags

Complete 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-system

Scenario 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 develop

Scenario 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-timeout

Scenario 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-profile

Pull Request Guidelines

Creating Pull Requests

PR Title Format:

PR titles show up in changelogs, Git history, and Slack notifications. Make them count.

Format:

<type>: <what you actually did>

Good PR titles:

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:

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: 50-72 characters. Longer means 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 passing

Code Review Checklist

For Reviewers:

  • Follows team conventions
  • No unnecessary complexity
  • Proper error handling
  • Security considerations addressed
  • Performance implications considered
  • Tests are adequate
  • Documentation updated
  • No debugging code left behind
  • Commit messages follow convention

Merging Strategies

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 staging

Why?

  • Squash merge: One commit per feature in develop. Clean history
  • Merge commit: Full history preserved for staging and production

Automating Quality Checks with Git Hooks

Git hooks catch bad code before it reaches the repository. They validate code quality, enforce commit standards, and prevent mistakes before review or CI.

What they prevent:

  • Linting errors and failing tests
  • Invalid commit message formats
  • Hardcoded secrets or API keys
  • Direct commits to protected branches
💡 Complete Git Hooks Guide

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

5 minutes to set up. Saves hours of debugging.

For 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 develop

During 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-feature

Before 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 develop

Communication Guidelines

Notify your team:

  • Before merging to develop, staging, or main
  • When deploying hotfixes
  • When blocked

Channels:

  • Slack/Teams: Quick updates, PR review requests
  • 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-feature

Issue 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 HEAD

Issue 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/main

Issue 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 this

Metrics and Monitoring

Track these to spot workflow issues:

Git Health Metrics

  • Average PR merge time: < 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 -l

Onboarding 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 merged

Summary 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 -d

Branch Lifecycle

How branches flow from creation to deletion:

Diagram

Branch lifespan by type:

Branch TypeCreated WhenDeleted WhenTypical Lifespan
feature/*Starting new workAfter merged to develop1-7 days
bugfix/*Fixing non-critical bugAfter merged to develop1-3 days
hotfix/*Production emergencyAfter merged to main2-4 hours
developProject startNever (permanent)Entire project
stagingProject startNever (permanent)Entire project
mainProject startNever (permanent)Entire project

Key points:

  • Feature branches are temporary. Delete after merging
  • Over 1 week old? Expect painful reviews
  • Over 2 weeks? Break the feature down

Protection Summary

BranchProtectionRequired ApprovalsAuto-Deploy
mainMaximum2 reviewersManual only
stagingHigh1 reviewerAuto to staging
developMedium1 reviewerAuto to dev
feature/*None-Optional preview

The Bottom Line

This workflow gives you:

  • No Friday disasters - Branch protection catches mistakes before prod
  • Code reviews that happen - Required, not optional
  • New devs who aren’t lost - Clear rules from day one
  • Confident deployments - Staging caught the bugs already

Adapt to your team size. Team of 3? Skip some ceremony. Growing to 10? Add guardrails. The point is structure so nobody nukes production.

Protect main this week. Add the rest as you go.

Next Steps: Implement This Today

A 3-week action plan:

Week 1: Foundation

Day 1 - Branch Protection (30 minutes)

  • Protect main with 2 required approvals
  • Protect staging and develop with 1 required approval
  • Enable status checks (CI/CD must pass)

Day 2 - Documentation (1 hour)

  • Add GIT_WORKFLOW.md to your repo (template below)
  • Share this guide with your team
  • Schedule a 30-minute team walkthrough

Day 3 - Git Hooks (1 hour)

  • Set up Husky and commitlint
  • Configure pre-commit linting
  • Test with a dummy commit
Week 2: Practice
  • Each team member practices with a feature branch
  • At least one PR per person
  • Refine based on feedback
  • Address questions in standup
💡 Week 3: Full Adoption
  • Move all active work to the new workflow
  • Monitor merge conflicts (should decrease)
  • Measure PR review times
  • Celebrate wins, learn from issues

Check the related guides or drop a comment below.

Additional Resources

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]

Protect main first. Add conventions as your team gets comfortable.