Git Workflows & Team Collaboration
Introduction
Effective Git workflows enable team collaboration and code quality. This guide covers Git Flow, GitHub Flow, trunk-based development, branching strategies, pull requests, code review, and Git best practices for professional teams.
1. Git Flow
# Git Flow - Traditional branching model
Branches:
- main: Production-ready code
- develop: Integration branch
- feature/*: New features
- release/*: Release preparation
- hotfix/*: Emergency fixes
# Initialize Git Flow
git flow init
# Start feature
git flow feature start user-authentication
# Work on feature
git add .
git commit -m "Add user authentication"
# Finish feature (merges to develop)
git flow feature finish user-authentication
# Start release
git flow release start 1.0.0
# Bump version, update changelog
git add .
git commit -m "Bump version to 1.0.0"
# Finish release (merges to main and develop, creates tag)
git flow release finish 1.0.0
# Start hotfix
git flow hotfix start security-patch
# Fix critical bug
git add .
git commit -m "Fix security vulnerability"
# Finish hotfix (merges to main and develop)
git flow hotfix finish security-patch
# Manual Git Flow (without git-flow extension)
# Feature branch
git checkout develop
git checkout -b feature/user-auth
# ... work ...
git checkout develop
git merge --no-ff feature/user-auth
git branch -d feature/user-auth
# Release branch
git checkout develop
git checkout -b release/1.0.0
# ... final adjustments ...
git checkout main
git merge --no-ff release/1.0.0
git tag -a v1.0.0 -m "Release 1.0.0"
git checkout develop
git merge --no-ff release/1.0.0
git branch -d release/1.0.0
# Hotfix branch
git checkout main
git checkout -b hotfix/critical-bug
# ... fix bug ...
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v1.0.1 -m "Hotfix 1.0.1"
git checkout develop
git merge --no-ff hotfix/critical-bug
git branch -d hotfix/critical-bug
2. GitHub Flow
# GitHub Flow - Simpler model for continuous delivery
Branches:
- main: Always deployable
- feature branches: Short-lived
# Create feature branch
git checkout -b feature/add-payment
# Make commits
git add .
git commit -m "Add payment integration"
# Push to remote
git push -u origin feature/add-payment
# Create Pull Request on GitHub
# Team reviews code
# CI/CD runs tests
# Merge to main
# Deploy automatically
# Update local main
git checkout main
git pull origin main
# Delete feature branch
git branch -d feature/add-payment
git push origin --delete feature/add-payment
# GitHub CLI workflow
gh auth login
# Create PR
gh pr create --title "Add payment integration" \
--body "Implements Stripe payment processing" \
--base main \
--head feature/add-payment
# List PRs
gh pr list
# Check PR status
gh pr status
# Review PR
gh pr review 123 --approve
gh pr review 123 --request-changes --body "Please add tests"
# Merge PR
gh pr merge 123 --squash --delete-branch
3. Trunk-Based Development
# Trunk-Based Development - Short-lived branches
Main concepts:
- Single main branch (trunk)
- Very short-lived feature branches (< 1 day)
- Frequent integration
- Feature flags for incomplete features
# Short-lived branch
git checkout -b quick-fix
# Make small change
git add .
git commit -m "Fix validation bug"
# Immediately merge
git checkout main
git pull --rebase
git merge quick-fix
git push origin main
# Delete branch
git branch -d quick-fix
# Feature flags for incomplete features
// config.js
export const features = {
newPaymentSystem: process.env.ENABLE_NEW_PAYMENT === 'true',
betaFeatures: process.env.ENABLE_BETA === 'true'
};
// Use in code
import { features } from './config';
if (features.newPaymentSystem) {
return newPaymentProcess(order);
} else {
return legacyPaymentProcess(order);
}
# CI/CD for trunk-based
# .github/workflows/trunk.yml
name: Trunk CI/CD
on:
push:
branches: [main]
jobs:
test-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: npm test
- name: Deploy to staging
if: success()
run: ./deploy.sh staging
- name: Run smoke tests
run: npm run test:smoke
- name: Deploy to production
if: success()
run: ./deploy.sh production
4. Pull Request Best Practices
# Pull Request Template
# .github/pull_request_template.md
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing completed
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-reviewed code
- [ ] Commented complex code
- [ ] Updated documentation
- [ ] No new warnings
- [ ] Added tests
- [ ] All tests pass
## Screenshots (if applicable)
## Related Issues
Fixes #123
Closes #456
# Good PR commits
# Before pushing, clean up commits
# Interactive rebase
git rebase -i HEAD~5
# Squash commits
pick a1b2c3d Add user model
squash e4f5g6h Fix typo
squash i7j8k9l Add tests
# Result: Single clean commit
git push --force-with-lease
# Conventional commits
git commit -m "feat: add user authentication"
git commit -m "fix: resolve login timeout issue"
git commit -m "docs: update API documentation"
git commit -m "refactor: improve database queries"
git commit -m "test: add unit tests for auth"
git commit -m "chore: update dependencies"
# Types:
# feat: New feature
# fix: Bug fix
# docs: Documentation
# style: Formatting
# refactor: Code restructuring
# test: Tests
# chore: Maintenance
# Semantic commit with scope
git commit -m "feat(auth): implement OAuth2 login"
git commit -m "fix(api): handle null response"
git commit -m "docs(readme): add installation steps"
5. Code Review Process
# Effective code review guidelines
Review checklist:
✓ Code works and meets requirements
✓ Tests are comprehensive and pass
✓ No obvious bugs or security issues
✓ Code is readable and maintainable
✓ Follows project conventions
✓ No unnecessary complexity
✓ Documentation is updated
✓ Performance is acceptable
# Review comments examples
# Good comments
"Consider extracting this logic into a helper function for reusability"
"This could cause a race condition if multiple users..."
"Nice solution! Have you considered the edge case where..."
"This test doesn't cover the error path"
# Bad comments
"This is wrong"
"I would do it differently"
"Why did you do it this way?"
# GitHub review commands
# Approve
gh pr review 123 --approve
# Request changes
gh pr review 123 --request-changes \
--body "Please address the following concerns..."
# Comment
gh pr review 123 --comment \
--body "Looks good overall, minor suggestion..."
# CODEOWNERS file
# .github/CODEOWNERS
# Global owners
* @team-leads
# Frontend
/src/components/** @frontend-team
/src/styles/** @frontend-team
# Backend
/api/** @backend-team
/database/** @backend-team @dba-team
# Infrastructure
/terraform/** @devops-team
/kubernetes/** @devops-team
/.github/workflows/** @devops-team
# Documentation
/docs/** @team-leads @tech-writers
README.md @team-leads
6. Branching Strategies
# Branch naming conventions
# Features
feature/user-authentication
feature/payment-integration
feature/dark-mode
# Bug fixes
bugfix/login-timeout
bugfix/cart-calculation
fix/memory-leak
# Hotfixes
hotfix/security-patch
hotfix/critical-bug
# Releases
release/v1.0.0
release/2024-01-sprint
# Environment-specific
staging
production
dev
# Personal branches
username/experiment
username/spike-graphql
# Branch protection rules
# Settings → Branches → Branch protection rules
Rules for 'main':
✓ Require pull request reviews before merging
- Required approvals: 2
- Dismiss stale reviews
- Require review from code owners
✓ Require status checks to pass
- CI/CD pipeline
- Unit tests
- Linting
- Security scan
✓ Require conversation resolution
✓ Require signed commits
✓ Include administrators
✓ Restrict pushes
✓ Require linear history
# Git aliases for productivity
# ~/.gitconfig
[alias]
# Status
st = status -s
# Checkout
co = checkout
cob = checkout -b
# Commit
ci = commit
cam = commit -am
# Branch
br = branch
brd = branch -d
# Log
lg = log --oneline --graph --all --decorate
last = log -1 HEAD --stat
# Diff
df = diff
dfc = diff --cached
# Stash
sl = stash list
sa = stash apply
ss = stash save
# Undo
undo = reset --soft HEAD^
unstage = reset HEAD --
# Pull
pl = pull --rebase
# Push
ps = push
psf = push --force-with-lease
# Cleanup
cleanup = "!git branch --merged | grep -v '\\*\\|main\\|develop' | xargs -n 1 git branch -d"
7. Merge Strategies
# Merge commit (default)
git merge feature-branch
# Pros: Full history, easy to revert
# Cons: Cluttered history with merge commits
# Squash merge
git merge --squash feature-branch
git commit -m "Add feature X"
# Pros: Clean history, single commit per feature
# Cons: Loses detailed commit history
# Rebase
git checkout feature-branch
git rebase main
git checkout main
git merge feature-branch
# Pros: Linear history, no merge commits
# Cons: Rewrites history, can be complex
# Fast-forward only
git merge --ff-only feature-branch
# Pros: Linear history when possible
# Cons: Fails if branches diverged
# Cherry-pick
git cherry-pick abc123
# Pick specific commits to apply
# Conflict resolution
git merge feature-branch
# CONFLICT in file.js
# Manually resolve conflicts
# Then:
git add file.js
git commit
# Or abort
git merge --abort
# Use merge tool
git mergetool
# Show conflicts
git diff --name-only --diff-filter=U
# Rerere (Reuse Recorded Resolution)
git config --global rerere.enabled true
# Git remembers conflict resolutions
8. Advanced Git Techniques
# Interactive rebase for cleaning history
git rebase -i HEAD~5
# Options:
# pick - use commit
# reword - use commit but edit message
# edit - use commit but stop for amending
# squash - combine with previous
# fixup - like squash but discard message
# drop - remove commit
# Bisect - Find bug introduction
git bisect start
git bisect bad # Current version is bad
git bisect good v1.0.0 # v1.0.0 was good
# Git checks out middle commit
# Test the code
git bisect good # or bad
# Repeat until bug found
git bisect reset
# Worktrees - Multiple working directories
git worktree add ../hotfix hotfix/critical-bug
cd ../hotfix
# Work on hotfix in separate directory
cd ../main-project
git worktree remove ../hotfix
# Reflog - Recover lost commits
git reflog
# Find lost commit
git checkout abc123
git branch recovered-branch
# Hooks for automation
# .git/hooks/pre-commit
#!/bin/bash
npm run lint
npm run test
# Make executable
chmod +x .git/hooks/pre-commit
# Husky for Git hooks
npm install -D husky
# package.json
{
"scripts": {
"prepare": "husky install"
}
}
npx husky add .husky/pre-commit "npm run lint"
npx husky add .husky/pre-push "npm run test"
# Commitlint for commit messages
npm install -D @commitlint/cli @commitlint/config-conventional
# commitlint.config.js
export default {
extends: ['@commitlint/config-conventional']
};
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
9. Git Security
# Signed commits with GPG
# Generate GPG key
gpg --full-generate-key
# List keys
gpg --list-secret-keys --keyid-format LONG
# Configure Git
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
# Sign commit
git commit -S -m "Signed commit"
# Verify signatures
git log --show-signature
# GitHub: Add GPG key to account
gpg --armor --export YOUR_KEY_ID
# Secrets scanning
# .gitignore
.env
.env.local
*.pem
*.key
id_rsa
credentials.json
# Remove secret from history
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/secret" \
--prune-empty --tag-name-filter cat -- --all
# Better: Use BFG Repo-Cleaner
bfg --delete-files secret.key
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Pre-commit hooks for secrets
# Install gitleaks
brew install gitleaks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/zricethezav/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
10. Best Practices
✓ Git Workflow Best Practices:
- ✓ Commit early and often with meaningful messages
- ✓ Keep commits atomic (one logical change per commit)
- ✓ Write descriptive commit messages (what and why)
- ✓ Use conventional commits format
- ✓ Review your own code before requesting review
- ✓ Keep pull requests small and focused
- ✓ Respond to review comments promptly
- ✓ Use branch protection rules
- ✓ Require code reviews for main branches
- ✓ Never force push to shared branches
- ✓ Use rebase for feature branches, merge for integration
- ✓ Tag releases with semantic versioning
- ✓ Keep main branch always deployable
- ✓ Delete merged branches promptly
- ✓ Use Git hooks for automation
Conclusion
Effective Git workflows enable team collaboration and code quality. Choose the right branching strategy for your team size and release cadence. Git Flow for structured releases, GitHub Flow for continuous deployment, or trunk-based for rapid iteration. Always prioritize code review, clean commits, and automated testing.
💡 Pro Tip: Use conventional commits with commitlint and semantic-release for automated versioning and changelog generation. Combined with proper CI/CD, this enables fully automated releases based on commit messages, eliminating manual version management.