
Managing Git Workflows
- 53 installs
- 426 repo stars
- Updated December 11, 2025
- ancoleman/ai-design-components
managing-git-workflows is a skill that helps teams pick a Git branching strategy and set up conventional commits, hooks, and review workflows.
About
A skill that structures Git branching, commit conventions, and collaboration workflows for teams. A developer uses it to pick a branching strategy, adopt conventional commits for automated versioning, wire up Git hooks for linting and tests, and organize monorepos with clear ownership. It matters because inconsistent Git practices slow reviews and break automated releases.
- Chooses between trunk-based development, GitHub Flow, and GitFlow by team maturity
- Sets up conventional commits, Husky Git hooks, and commit-msg validation for quality gates
- Covers monorepo tooling (Nx, Turborepo), CODEOWNERS, and merge vs rebase vs squash guidance
Managing Git Workflows by the numbers
- 53 all-time installs (skills.sh)
- Ranked #290 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
managing-git-workflows capabilities & compatibility
- Capabilities
- branching strategy · conventional commits · git hooks · code review setup
- Works with
- github
- Use cases
- code review · ci cd
- Runs
- Runs locally
- Pricing
- Free
What managing-git-workflows says it does
Implement structured Git workflows for team collaboration, code quality, and automated releases.
`feat` - New feature (MINOR version bump: 0.1.0)
**⚠️ Never rebase:** Public branches (main, develop) or commits already pushed and used by others
npx skills add https://github.com/ancoleman/ai-design-components --skill managing-git-workflowsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 53 |
|---|---|
| repo stars | ★ 426 |
| Last updated | December 11, 2025 |
| Repository | ancoleman/ai-design-components ↗ |
What it does
Choose a Git branching strategy, enforce conventional commits and hooks, and set up code review and monorepo ownership.
Who is it for?
Teams standardizing branching, commits, and review gates for automated releases
Skip if: Learning basic Git commands for a solo first-time user
When should I use this skill?
Choosing a branching strategy, adopting conventional commits, or setting up Git hooks and code review rules
What you get
A chosen branching strategy with conventional commits, hooks, and review gates in place
- branching strategy decision
- conventional-commit config
- Git hooks
By the numbers
- 3 branching strategies compared (trunk-based, GitHub Flow, GitFlow)
- 3 Git hook types (pre-commit, commit-msg, pre-push)
Files
Git Workflows
Implement structured Git workflows for team collaboration, code quality, and automated releases. This skill covers branching strategies, conventional commit formats, Git hooks, and monorepo management patterns.
When to Use This Skill
Use this skill when:
- Choosing a branching strategy for a new project or team
- Implementing consistent commit message formats
- Setting up Git hooks for linting, testing, or validation
- Managing monorepos with multiple projects
- Establishing code review workflows
- Automating versioning and releases
Quick Decision: Which Branching Strategy?
Trunk-Based Development
Use when the team has strong CI/CD automation, comprehensive test coverage (80%+), and deploys frequently (daily or more). Short-lived branches merge within 1 day. Requires feature flags for incomplete features.
Best for: High-velocity teams with mature DevOps practices (Google, Facebook, Netflix)
GitHub Flow
Use for web applications with continuous deployment. Main branch always represents production. Simple PR-based workflow for small to medium teams (2-20 developers).
Best for: Startups, SaaS products, open-source projects
GitFlow
Use when supporting multiple production versions simultaneously, requiring formal QA cycles, or following scheduled releases (monthly, quarterly). More complex but structured.
Best for: Enterprise software, mobile apps with App Store releases, on-premise products
For detailed branching patterns with examples, see references/branching-strategies.md.
Conventional Commits
Structure commit messages for automated versioning and changelog generation:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Common Types:
feat- New feature (MINOR version bump: 0.1.0)fix- Bug fix (PATCH version bump: 0.0.1)docs- Documentation onlyrefactor- Code restructuring without feature changetest- Adding or updating testschore- Maintenance tasks
Breaking Changes:
- Add
!after type:feat!:orfix!: - Add
BREAKING CHANGE:in footer - Results in MAJOR version bump (1.0.0)
Examples:
git commit -m "feat(auth): add JWT token validation"
git commit -m "fix: resolve race condition in user login"
git commit -m "feat!: redesign authentication API
BREAKING CHANGE: Auth endpoints now require API version header"For complete specification and tooling setup, see references/conventional-commits.md.
Git Hooks for Quality Gates
Automate code quality checks at key workflow points:
pre-commit - Run before commit is created
- Linting (ESLint, Prettier)
- Formatting checks
- Quick tests
commit-msg - Validate commit message format
- Enforce conventional commits
- Check message length
pre-push - Run before pushing to remote
- Full test suite
- Prevent force push to protected branches
Quick Setup with Husky:
npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional
npx husky init
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'For complete hook configuration and examples, see references/git-hooks-guide.md.
Monorepo Management
Build Tool Selection
Nx - Best for TypeScript/JavaScript monorepos
- Dependency graph analysis
- Affected commands (only rebuild changed projects)
- Distributed caching
Turborepo - Best for Next.js/React applications
- Fast incremental builds
- Remote caching
- Simple configuration
Sparse Checkout - For large repos when full clone not needed
git sparse-checkout init --cone
git sparse-checkout set apps/web libs/ui-componentsCode Ownership
Use .github/CODEOWNERS to define ownership:
# Default owners
* @org/engineering
# Apps ownership
/apps/web/ @org/web-team
/apps/mobile/ @org/mobile-team
# Security-critical
/libs/auth/ @org/security-team @org/principal-engineersFor detailed monorepo patterns, see references/monorepo-patterns.md.
Merge vs Rebase
Merge Commits
Use when preserving complete history is important:
git checkout main
git merge feature-branchWhen: Multiple developers on feature branch, want to see integration point
Squash and Merge
Use for clean, linear history:
git checkout main
git merge --squash feature-branch
git commit -m "feat: add user authentication"When: Feature has many WIP commits, want clean main branch history
Rebase
Use for linear history without merge commits:
git checkout feature-branch
git rebase mainWhen: Updating feature branch, working alone, cleaning up before PR
⚠️ Never rebase: Public branches (main, develop) or commits already pushed and used by others
Code Review Workflows
Pull Request Template
Create .github/PULL_REQUEST_TEMPLATE.md:
## Description
<!-- Brief description of changes -->
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-reviewed code
- [ ] Added tests
- [ ] Updated documentation
- [ ] Tests pass locallyBranch Protection Rules
Enforce quality gates via repository settings:
- Require pull request reviews (2+ approvals)
- Require status checks (build, tests, lint)
- Require branches up to date before merging
- Restrict force pushes and deletions
For complete code review setup, see references/code-review-workflows.md.
Branch Naming Conventions
Use consistent naming for clarity:
feature/user-authentication- New featuresbugfix/login-error- Bug fixeshotfix/critical-security-issue- Urgent production fixesdocs/api-documentation- Documentation changesrefactor/database-layer- Code refactoring
Validate branch names with Git hooks (see scripts/check-branch-name.sh).
Advanced Techniques
Cherry-Picking for Hotfixes
Apply specific commits to other branches:
git checkout main
git commit -m "fix: resolve critical security issue"
# Commit hash: a1b2c3d
git checkout release/1.5
git cherry-pick a1b2c3dGit LFS for Large Files
Track large files separately from code:
git lfs install
git lfs track "*.psd"
git lfs track "*.mp4"
git add .gitattributesRelease Tagging
Mark production releases:
git tag -a v1.2.0 -m "Release version 1.2.0"
git push origin v1.2.0Interactive Rebase
Clean up commit history before PR:
git rebase -i HEAD~3
# Squash WIP commits, reword messages, reorder commitsFor detailed examples, see examples/ directory.
Automated Release Workflow
Combine conventional commits with CI/CD for automated versioning:
1. Commits - Follow conventional format 2. Analysis - Semantic Release analyzes commit types 3. Version - Determines MAJOR.MINOR.PATCH bump 4. Changelog - Auto-generates from commits 5. Tag - Creates Git tag 6. Publish - Deploys to npm, GitHub releases, etc.
See examples/semantic-release-setup/ for complete configuration.
Tool Recommendations
Git Hooks:
- Husky - Simplify hook management (most popular)
- lint-staged - Run linters only on staged files (performance)
Commit Validation:
- Commitlint - Enforce conventional commits
- Semantic Release - Automated versioning
Monorepo Build:
- Nx - TypeScript/JavaScript (Google, AWS use this)
- Turborepo - Next.js/React (Vercel)
Large Files:
- Git LFS - Store large binary files
All tools validated via Context7 with high trust scores (December 2025).
Integration with Other Skills
building-ci-pipelines - Git workflows trigger CI/CD pipelines, branch protection enforces CI checks
writing-github-actions - GitHub Actions automate workflow steps (releases, PR checks)
infrastructure-as-code - IaC repos need structured workflows, GitOps uses Git as source of truth
testing-strategies - Git hooks enforce test requirements, pre-push runs test suites
security-hardening - Git hooks prevent secrets, signed commits verify identity, CODEOWNERS enforce security reviews
Quick Reference
Trunk-Based Development Workflow
git checkout -b feature/add-login main
git add .
git commit -m "feat: add login form component"
git rebase origin/main # Stay up to date
git push origin feature/add-login
# PR → merge → delete branch (within 24 hours)GitHub Flow Workflow
git checkout -b feature/user-auth main
git commit -m "feat: add JWT authentication"
git commit -m "test: add auth tests"
git push origin feature/user-auth
# Open PR → review → merge → deploy → delete branchGitFlow Workflow
# Feature
git checkout -b feature/user-profile develop
git commit -m "feat: add user profile"
git checkout develop
git merge --no-ff feature/user-profile
# Release
git checkout -b release/1.1.0 develop
git checkout main
git merge --no-ff release/1.1.0
git tag -a v1.1.0 -m "Release 1.1.0"
# Hotfix
git checkout -b hotfix/critical-bug main
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v1.1.1 -m "Hotfix 1.1.1"Validation Scripts
Run automated checks:
scripts/validate-commit-msg.sh- Validate commit message formatscripts/check-branch-name.sh- Validate branch naming conventionscripts/setup-hooks.sh- Automated hook installation
Execute scripts directly (token-free) for validation.
#!/bin/bash
# GitFlow Complete Workflow Example
# This script demonstrates a complete GitFlow workflow including features, releases, and hotfixes
set -e # Exit on error
echo "🚀 GitFlow Workflow Example"
echo "==========================="
echo ""
# Initialize GitFlow
echo "📝 Step 1: Initialize GitFlow"
echo "
GitFlow uses two main branches:
- main: Production-ready code
- develop: Integration branch for next release
"
git checkout -b develop main
echo "✅ Created develop branch from main"
echo ""
# Feature Development
echo "📝 Step 2: Feature Development"
echo ""
# Feature 1: User Profile
echo "Creating feature/user-profile..."
git checkout -b feature/user-profile develop
echo "// User profile component" > src/components/UserProfile.tsx
git add src/components/UserProfile.tsx
git commit -m "feat(profile): add user profile component"
echo "// User profile API" > src/api/profile.ts
git add src/api/profile.ts
git commit -m "feat(api): add user profile endpoints"
echo "// Profile tests" > tests/profile.test.ts
git add tests/profile.test.ts
git commit -m "test(profile): add user profile tests"
# Merge feature to develop
git checkout develop
git merge --no-ff feature/user-profile -m "Merge feature: user profile
Added user profile functionality with full test coverage."
git branch -d feature/user-profile
echo "✅ Feature user-profile merged to develop"
echo ""
# Feature 2: Notifications
echo "Creating feature/notifications..."
git checkout -b feature/notifications develop
echo "// Notification service" > src/services/notifications.ts
git add src/services/notifications.ts
git commit -m "feat(notifications): add notification service"
echo "// Email notifications" > src/services/email.ts
git add src/services/email.ts
git commit -m "feat(notifications): add email notification support"
# Merge feature to develop
git checkout develop
git merge --no-ff feature/notifications -m "Merge feature: notifications
Added notification system with email support."
git branch -d feature/notifications
echo "✅ Feature notifications merged to develop"
echo ""
# Release Process
echo "📝 Step 3: Release Process"
echo ""
# Create release branch
echo "Creating release/1.1.0..."
git checkout -b release/1.1.0 develop
# Prepare release (version bumps, changelog)
echo '{
"version": "1.1.0"
}' > package.json
git add package.json
git commit -m "chore(release): bump version to 1.1.0"
echo "# Changelog
## [1.1.0] - 2025-12-04
### Features
- User profile functionality
- Notification system with email support
### Bug Fixes
- Minor UI improvements
" > CHANGELOG.md
git add CHANGELOG.md
git commit -m "docs(changelog): update changelog for 1.1.0"
# Bug fixes on release branch (last-minute fixes only)
echo "// Fix minor UI issue" > src/bugfix.ts
git add src/bugfix.ts
git commit -m "fix(ui): resolve alignment issue in profile page"
echo "✅ Release 1.1.0 prepared"
echo ""
# Merge release to main
echo "Merging release to main..."
git checkout main
git merge --no-ff release/1.1.0 -m "Release version 1.1.0
Features:
- User profile functionality
- Notification system
Bug fixes:
- UI alignment issues
"
# Tag the release
git tag -a v1.1.0 -m "Release version 1.1.0"
echo "✅ Release 1.1.0 merged to main and tagged"
echo ""
# Merge release back to develop
echo "Merging release back to develop..."
git checkout develop
git merge --no-ff release/1.1.0 -m "Merge release 1.1.0 back to develop"
# Delete release branch
git branch -d release/1.1.0
echo "✅ Release branch merged back to develop and deleted"
echo ""
# Hotfix Process
echo "📝 Step 4: Hotfix Process"
echo ""
# Critical bug discovered in production
echo "Creating hotfix/critical-security-issue..."
git checkout -b hotfix/critical-security-issue main
echo "// Security fix" > src/security/patch.ts
git add src/security/patch.ts
git commit -m "fix(security): resolve critical authentication vulnerability
CVE-2025-12345: Fixed authentication bypass vulnerability
in JWT token validation.
BREAKING CHANGE: Tokens issued before this fix are invalidated."
# Update version for hotfix
echo '{
"version": "1.1.1"
}' > package.json
git add package.json
git commit -m "chore(hotfix): bump version to 1.1.1"
echo "✅ Hotfix prepared"
echo ""
# Merge hotfix to main
echo "Merging hotfix to main..."
git checkout main
git merge --no-ff hotfix/critical-security-issue -m "Hotfix version 1.1.1
Security Fix:
- Resolved critical authentication vulnerability (CVE-2025-12345)
"
# Tag the hotfix
git tag -a v1.1.1 -m "Hotfix version 1.1.1 - Security patch"
echo "✅ Hotfix 1.1.1 merged to main and tagged"
echo ""
# Merge hotfix back to develop
echo "Merging hotfix back to develop..."
git checkout develop
git merge --no-ff hotfix/critical-security-issue -m "Merge hotfix 1.1.1 to develop"
# If release branch exists, merge there too
# git checkout release/1.2.0
# git merge --no-ff hotfix/critical-security-issue
# Delete hotfix branch
git branch -d hotfix/critical-security-issue
echo "✅ Hotfix branch merged back to develop and deleted"
echo ""
# Summary
echo "📝 GitFlow Summary"
echo "=================="
echo ""
echo "Branch Structure:"
echo " main (production)"
echo " └── tags: v1.0.0, v1.1.0, v1.1.1"
echo " develop (integration)"
echo " ├── feature/user-profile (merged)"
echo " └── feature/notifications (merged)"
echo " release/1.1.0 (merged, deleted)"
echo " hotfix/critical-security-issue (merged, deleted)"
echo ""
echo "Workflow Steps:"
echo " 1. Features branch from develop"
echo " 2. Features merge back to develop (--no-ff)"
echo " 3. Release branches from develop"
echo " 4. Release merges to main (tagged) and back to develop"
echo " 5. Hotfixes branch from main"
echo " 6. Hotfixes merge to main (tagged) and back to develop"
echo ""
echo "Key Principles:"
echo " ✓ main and develop are long-lived branches"
echo " ✓ Never commit directly to main or develop"
echo " ✓ Always use --no-ff for merges (preserve history)"
echo " ✓ Tag all releases on main branch"
echo " ✓ Hotfixes go to both main and develop"
echo ""
echo "Commands Reference:"
echo ""
echo "Feature workflow:"
echo " git checkout -b feature/name develop"
echo " # Make commits"
echo " git checkout develop"
echo " git merge --no-ff feature/name"
echo " git branch -d feature/name"
echo ""
echo "Release workflow:"
echo " git checkout -b release/X.Y.Z develop"
echo " # Version bump and final fixes"
echo " git checkout main"
echo " git merge --no-ff release/X.Y.Z"
echo " git tag -a vX.Y.Z -m 'Release X.Y.Z'"
echo " git checkout develop"
echo " git merge --no-ff release/X.Y.Z"
echo " git branch -d release/X.Y.Z"
echo ""
echo "Hotfix workflow:"
echo " git checkout -b hotfix/name main"
echo " # Make fix and version bump"
echo " git checkout main"
echo " git merge --no-ff hotfix/name"
echo " git tag -a vX.Y.Z -m 'Hotfix X.Y.Z'"
echo " git checkout develop"
echo " git merge --no-ff hotfix/name"
echo " git branch -d hotfix/name"
echo ""
echo "✅ GitFlow workflow complete!"
#!/bin/bash
# GitHub Flow Complete Workflow Example
# This script demonstrates a complete GitHub Flow workflow from feature creation to deployment
set -e # Exit on error
echo "🚀 GitHub Flow Workflow Example"
echo "================================"
echo ""
# Step 1: Create feature branch from main
echo "📝 Step 1: Create feature branch from main"
git checkout main
git pull origin main
git checkout -b feature/user-authentication
echo "✅ Created feature branch: feature/user-authentication"
echo ""
# Step 2: Make changes and commit
echo "📝 Step 2: Make changes with conventional commits"
# Simulate file changes
echo "// JWT authentication middleware" > src/auth/jwt.ts
git add src/auth/jwt.ts
git commit -m "feat(auth): add JWT authentication middleware
Implements JWT token generation and validation
for user authentication."
echo "// User login endpoint" > src/api/login.ts
git add src/api/login.ts
git commit -m "feat(api): add user login endpoint
POST /api/login endpoint that accepts credentials
and returns JWT token."
echo "// Authentication tests" > tests/auth.test.ts
git add tests/auth.test.ts
git commit -m "test(auth): add authentication tests
Unit tests for JWT middleware and login endpoint.
Coverage: 95%"
echo "✅ Created 3 commits with conventional format"
echo ""
# Step 3: Push and create PR
echo "📝 Step 3: Push branch and create pull request"
git push origin feature/user-authentication
# Create PR using GitHub CLI (if available)
if command -v gh &> /dev/null; then
gh pr create \
--title "Add user authentication" \
--body "## Description
Implements JWT-based user authentication.
## Changes
- JWT middleware for token validation
- Login endpoint for credential verification
- Comprehensive test coverage
## Type of Change
- [x] New feature
## Testing
- [x] Unit tests added (95% coverage)
- [x] Integration tests added
- [x] Manual testing completed
Closes #123"
echo "✅ Pull request created via GitHub CLI"
else
echo "⚠️ GitHub CLI not installed. Create PR manually at:"
echo " https://github.com/org/repo/compare/main...feature/user-authentication"
fi
echo ""
# Step 4: Code review process
echo "📝 Step 4: Code review process"
echo "
Code review workflow:
1. Request review from code owners
2. Reviewers provide feedback
3. Address feedback with additional commits
4. Request re-review after changes
5. Merge after approval
To address feedback:
git add <files>
git commit -m 'fix(auth): handle edge case in token validation'
git push origin feature/user-authentication
"
echo ""
# Step 5: Merge to main
echo "📝 Step 5: Merge to main (after approval)"
echo "
Merge options:
1. Squash and merge (recommended for clean history)
- Combines all commits into one
- Main branch has linear history
2. Merge commit (preserve all commits)
- Keeps all individual commits
- Creates merge commit
3. Rebase and merge (linear history)
- Replays commits on top of main
- No merge commit
To merge via GitHub CLI:
gh pr merge --squash --delete-branch
Or merge via GitHub UI:
- Click 'Squash and merge'
- Confirm merge
- Delete branch
"
echo ""
# Step 6: Post-merge cleanup
echo "📝 Step 6: Post-merge cleanup"
echo "
After merge:
1. Automated deployment triggers
2. CI/CD pipeline runs
3. Feature deployed to production
4. Branch is deleted automatically
Local cleanup:
git checkout main
git pull origin main
git branch -d feature/user-authentication
"
echo ""
# Example of continuous deployment
echo "📝 Step 7: Continuous deployment"
echo "
GitHub Actions automatically:
1. Runs tests
2. Builds application
3. Deploys to staging
4. Runs smoke tests
5. Deploys to production
6. Notifies team
See .github/workflows/deploy.yml for configuration
"
echo ""
echo "✅ GitHub Flow workflow complete!"
echo ""
echo "Key Principles:"
echo " ✓ Main branch is always deployable"
echo " ✓ Every merge triggers deployment"
echo " ✓ Code review via pull requests"
echo " ✓ Automated testing and deployment"
echo " ✓ Fast feedback loop"
skill: "managing-git-workflows"
version: "1.0"
domain: "developer"
base_outputs:
# Git hooks configuration
- path: ".husky/pre-commit"
must_contain: ["lint-staged", "#!/usr/bin/env sh"]
- path: ".husky/commit-msg"
must_contain: ["commitlint", "--edit"]
- path: ".husky/pre-push"
must_contain: ["npm test", "branch"]
# Commit message validation
- path: "commitlint.config.js"
must_contain: ["@commitlint/config-conventional", "type-enum"]
# Code formatting and linting
- path: ".prettierrc"
must_contain: ["singleQuote", "printWidth"]
- path: ".eslintrc.js"
must_contain: ["extends", "rules"]
- path: "package.json"
must_contain: ["lint-staged", "husky", "prepare"]
# Pull request templates
- path: ".github/PULL_REQUEST_TEMPLATE.md"
must_contain: ["## Description", "## Type of Change", "## Checklist"]
# Basic gitignore
- path: ".gitignore"
must_contain: ["node_modules", ".env"]
conditional_outputs:
maturity:
starter:
# Minimal setup for small teams
- path: ".github/CODEOWNERS"
must_contain: ["* @"]
- path: ".github/workflows/pr-checks.yml"
must_contain: ["pull_request", "build", "test"]
intermediate:
# Enhanced setup with multiple templates
- path: ".github/PULL_REQUEST_TEMPLATE/feature.md"
must_contain: ["## Feature Description", "## Testing", "## Documentation"]
- path: ".github/PULL_REQUEST_TEMPLATE/bugfix.md"
must_contain: ["## Bug Description", "## Root Cause", "## Solution"]
- path: ".github/labeler.yml"
must_contain: ["frontend", "backend", "documentation"]
- path: ".github/workflows/pr-validation.yml"
must_contain: ["validate-pr-title", "check-pr-size", "label-pr"]
# Monorepo setup
- path: "nx.json"
must_contain: ["targetDefaults", "affected"]
- path: ".github/CODEOWNERS"
must_contain: ["/apps/", "/libs/", "@org/"]
advanced:
# Full enterprise setup with automated releases
- path: ".releaserc.json"
must_contain: ["@semantic-release", "branches", "plugins"]
- path: ".github/workflows/release.yml"
must_contain: ["semantic-release", "GITHUB_TOKEN", "npm publish"]
- path: ".github/workflows/require-issue.yml"
must_contain: ["issue reference", "Closes", "Fixes"]
- path: ".github/workflows/pr-size.yml"
must_contain: ["pr-size-labeler", "size/"]
# Advanced branch protection (documented in README/CONTRIBUTING)
- path: "CONTRIBUTING.md"
must_contain: ["branch protection", "code review", "conventional commits"]
# Git LFS configuration
- path: ".gitattributes"
must_contain: ["filter=lfs", "diff=lfs"]
# Turborepo/Nx advanced config
- path: "turbo.json"
must_contain: ["pipeline", "cache", "dependsOn"]
ci_cd:
github_actions:
- path: ".github/workflows/pr-checks.yml"
must_contain: ["pull_request", "branches", "jobs"]
- path: ".github/workflows/pr-validation.yml"
must_contain: ["validate-pr-title", "amannn/action-semantic-pull-request"]
gitlab_ci:
- path: ".gitlab-ci.yml"
must_contain: ["stages", "test", "merge_request"]
- path: ".gitlab/merge_request_templates/Default.md"
must_contain: ["## Description", "## Changes"]
jenkins:
- path: "Jenkinsfile"
must_contain: ["pipeline", "stage", "git"]
- path: ".github/PULL_REQUEST_TEMPLATE.md"
must_contain: ["## Description", "## Checklist"]
scaffolding:
# Directory structure for GitHub workflows
- ".github/"
- ".github/workflows/"
- ".github/PULL_REQUEST_TEMPLATE/"
- ".husky/"
# Common documentation structure
- "docs/"
# Monorepo structure (if applicable)
- "apps/"
- "libs/"
- "packages/"
metadata:
primary_blueprints: ["ci-cd"]
secondary_blueprints: ["security", "developer-productivity"]
contributes_to:
- "Git workflow automation"
- "Code quality gates"
- "Pull request workflows"
- "Automated versioning"
- "Monorepo management"
- "Branch protection"
- "Code review processes"
common_file_patterns:
git_hooks:
- ".husky/*"
- ".git/hooks/*"
github:
- ".github/PULL_REQUEST_TEMPLATE.md"
- ".github/PULL_REQUEST_TEMPLATE/*.md"
- ".github/CODEOWNERS"
- ".github/workflows/*.yml"
- ".github/labeler.yml"
commit_validation:
- "commitlint.config.js"
- ".commitlintrc.json"
code_quality:
- ".eslintrc.js"
- ".eslintrc.json"
- ".prettierrc"
- ".prettierrc.json"
- ".editorconfig"
monorepo:
- "nx.json"
- "workspace.json"
- "turbo.json"
- "lerna.json"
release:
- ".releaserc.json"
- ".releaserc.js"
- "release.config.js"
git_config:
- ".gitignore"
- ".gitattributes"
- ".git-blame-ignore-revs"
integration_points:
building_ci_pipelines:
description: "Git workflows trigger CI/CD pipelines, branch protection enforces CI checks"
shared_files: [".github/workflows/pr-checks.yml", ".github/workflows/release.yml"]
writing_github_actions:
description: "GitHub Actions automate workflow steps (releases, PR checks)"
shared_files: [".github/workflows/*.yml"]
infrastructure_as_code:
description: "IaC repos need structured workflows, GitOps uses Git as source of truth"
shared_files: [".github/CODEOWNERS", ".github/workflows/deploy.yml"]
testing_strategies:
description: "Git hooks enforce test requirements, pre-push runs test suites"
shared_files: [".husky/pre-push", ".husky/pre-commit"]
security_hardening:
description: "Git hooks prevent secrets, signed commits verify identity, CODEOWNERS enforce security reviews"
shared_files: [".github/CODEOWNERS", ".husky/pre-commit"]
tool_ecosystem:
git_hooks:
- name: "Husky"
purpose: "Simplify Git hooks management"
config_files: [".husky/*", "package.json"]
- name: "lint-staged"
purpose: "Run linters only on staged files"
config_files: ["package.json", ".lintstagedrc.json"]
commit_validation:
- name: "Commitlint"
purpose: "Enforce conventional commits"
config_files: ["commitlint.config.js", ".commitlintrc.json"]
- name: "Semantic Release"
purpose: "Automated versioning and releases"
config_files: [".releaserc.json", "release.config.js"]
monorepo_tools:
- name: "Nx"
purpose: "TypeScript/JavaScript monorepo build system"
config_files: ["nx.json", "workspace.json"]
- name: "Turborepo"
purpose: "Next.js/React monorepo build system"
config_files: ["turbo.json"]
large_files:
- name: "Git LFS"
purpose: "Store large binary files"
config_files: [".gitattributes"]
branching_strategies:
trunk_based:
description: "High-velocity teams with strong CI/CD, feature flags, <1 day branches"
files: [".github/workflows/deploy.yml", ".husky/pre-push"]
maturity: "advanced"
github_flow:
description: "Web apps with continuous deployment, main = production"
files: [".github/PULL_REQUEST_TEMPLATE.md", ".github/workflows/pr-checks.yml"]
maturity: "starter"
gitflow:
description: "Multiple production versions, formal QA cycles, scheduled releases"
files: [".github/workflows/release.yml", "CONTRIBUTING.md"]
maturity: "intermediate"
validation:
required_sections:
- "base_outputs"
- "conditional_outputs"
- "metadata"
file_path_format: "unix" # Forward slashes only
must_document:
- "Branching strategy choice rationale"
- "Commit message conventions"
- "Code review requirements"
- "Merge strategies"
Git Branching Strategies
Detailed patterns for trunk-based development, GitHub Flow, and GitFlow with complete workflow examples.
Table of Contents
1. Trunk-Based Development 2. GitHub Flow 3. GitFlow 4. Feature Branching 5. Comparison Matrix
Trunk-Based Development
Overview
High-velocity workflow where developers commit to main (trunk) frequently, using short-lived branches that merge within 1 day.
When to Use
- ✅ Strong CI/CD automation in place
- ✅ Comprehensive automated test coverage (80%+)
- ✅ Team practices continuous integration
- ✅ Feature flags hide incomplete features
- ✅ Deployments are frequent (daily or more)
- ✅ Team is experienced with Git and testing
Branch Structure
main (trunk) - Always deployable
├── feature/short-lived-1 (0-1 days)
├── feature/short-lived-2 (0-1 days)
└── feature/short-lived-3 (0-1 days)Complete Workflow
# 1. Create short-lived feature branch from main
git checkout -b feature/add-login main
# 2. Make small, incremental changes
git add src/components/LoginForm.tsx
git commit -m "feat: add login form component"
# 3. Update with latest main frequently (multiple times per day)
git fetch origin
git rebase origin/main
# 4. Push and create pull request
git push origin feature/add-login
# 5. After review, merge immediately
# (via GitHub UI or CLI)
git checkout main
git merge feature/add-login
# 6. Delete branch immediately after merge
git branch -d feature/add-login
git push origin --delete feature/add-loginKey Principles
Branch Lifetime:
- Branches live <24 hours (ideally <4 hours)
- Commit to main multiple times per day
- No long-lived feature branches
Feature Flags: Hide incomplete features from users while integrating code:
// Example: React component with feature flag
if (featureFlags.newLogin && user.isBetaTester) {
return <NewLoginForm />;
}
return <OldLoginForm />;Continuous Integration:
- CI/CD runs on every commit to main
- Broken builds are top priority to fix
- Automated deployment to production
Team Practices:
- Pair programming or immediate code review
- Small pull requests (100-300 lines)
- Tests written alongside code
Example: Adding a New Feature
# Day 1, Morning (9 AM)
git checkout -b feature/user-notifications main
# Add notification model (30 min)
git add src/models/Notification.ts
git commit -m "feat(notifications): add notification model"
# Add API endpoints (1 hour)
git add src/api/notifications.ts
git commit -m "feat(notifications): add API endpoints"
# Update with latest main
git fetch origin
git rebase origin/main
# Push and create PR
git push origin feature/user-notifications
gh pr create --title "Add user notifications (behind feature flag)"
# Day 1, Afternoon (2 PM)
# After review and CI passes
git checkout main
git pull origin main
git merge feature/user-notifications
git push origin main
# Feature deployed but hidden behind flag
# Enable for beta testers only
# Day 2-3: Iterate on feature
# Day 4: Enable for all users
# featureFlags.userNotifications = true---
GitHub Flow
Overview
Simple branch-based workflow where main is always deployable. Feature branches are merged via pull requests after code review.
When to Use
- ✅ Building web applications
- ✅ Main branch always represents production
- ✅ Continuous deployment is the goal
- ✅ Simple, understandable workflow needed
- ✅ Small to medium team size (2-20 developers)
- ✅ Single production environment
Branch Structure
main (always deployable) - Production
├── feature/user-auth
├── feature/payment-integration
├── bugfix/login-error
└── docs/api-documentationComplete Workflow
# 1. Create feature branch from main
git checkout -b feature/user-auth main
# 2. Make commits with descriptive messages
git add src/auth/jwt.ts
git commit -m "feat: add JWT authentication middleware"
git add src/auth/login.ts
git commit -m "feat: add login endpoint"
git add tests/auth.test.ts
git commit -m "test: add authentication tests"
git add docs/api/auth.md
git commit -m "docs: document authentication API"
# 3. Push and open pull request
git push origin feature/user-auth
# Open PR via GitHub CLI or web UI
gh pr create \
--title "Add JWT authentication" \
--body "Implements user authentication with JWT tokens. Closes #123"
# 4. Code review and discussion
# Address feedback by pushing more commits
git add src/auth/jwt.ts
git commit -m "fix: handle expired tokens properly"
git push origin feature/user-auth
# 5. Merge to main after approval
# (via GitHub UI - squash and merge recommended)
# 6. Automated deployment triggers
# CI/CD deploys to production automatically
# 7. Delete branch after merge
git branch -d feature/user-auth
git push origin --delete feature/user-authKey Principles
Main Branch:
- Always deployable to production
- Protected by branch rules (no direct commits)
- Every merge triggers deployment
Pull Requests:
- Code review required before merge
- Status checks must pass (CI, tests, linting)
- Descriptive PR descriptions with context
Branch Naming: Use type prefixes for clarity:
feature/description- New featuresbugfix/description- Bug fixesdocs/description- Documentationrefactor/description- Code refactoring
Merge Strategy: Squash and merge recommended for clean history:
- Combines all feature commits into one
- Main branch has linear, readable history
- Each commit on main represents complete feature
Example: Bug Fix Workflow
# User reports login error (Issue #456)
# 1. Create bugfix branch
git checkout -b bugfix/login-timeout main
# 2. Reproduce and fix issue
git add src/auth/login.ts
git commit -m "fix: increase login timeout to 10 seconds"
# 3. Add regression test
git add tests/auth.test.ts
git commit -m "test: add test for login timeout"
# 4. Push and create PR
git push origin bugfix/login-timeout
gh pr create \
--title "Fix login timeout issue" \
--body "Fixes #456. Increased timeout and added regression test."
# 5. After review and CI passes, merge via GitHub UI
# 6. Verify deployment in production
# Monitor error logs for the issue
# 7. Clean up local branch
git checkout main
git pull origin main
git branch -d bugfix/login-timeout---
GitFlow
Overview
Structured workflow with multiple long-lived branches. Separates development, release preparation, and production code.
When to Use
- ✅ Multiple production versions supported simultaneously
- ✅ Scheduled releases (monthly, quarterly)
- ✅ Formal QA cycle required before release
- ✅ Hotfixes need to bypass normal release cycle
- ✅ Enterprise environment with change management
- ✅ Mobile apps with App Store release cycles
Branch Structure
main (production) - Tagged releases only
└── tags: v1.0.0, v1.1.0, v2.0.0
develop (integration) - Next release
├── feature/user-profile
├── feature/notifications
└── feature/settings
release/1.1.0 - Release preparation
└── Bug fixes and version bumps only
hotfix/critical-bug - Urgent production fixesBranch Types
Long-Lived Branches:
main- Production code, tagged releases onlydevelop- Integration branch for next release
Short-Lived Branches:
feature/*- New features (branch from develop)release/*- Release preparation (branch from develop)hotfix/*- Urgent fixes (branch from main)
Complete Workflow
Feature Development
# 1. Create feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/user-profile develop
# 2. Develop feature
git add src/components/UserProfile.tsx
git commit -m "feat: add user profile page"
git add src/api/user.ts
git commit -m "feat: add user profile API"
git add tests/user-profile.test.tsx
git commit -m "test: add user profile tests"
# 3. Merge feature to develop (no fast-forward)
git checkout develop
git merge --no-ff feature/user-profile -m "Merge feature: user profile"
# 4. Delete feature branch
git branch -d feature/user-profile
# 5. Push develop
git push origin developRelease Workflow
# 1. Create release branch from develop
git checkout -b release/1.1.0 develop
# 2. Prepare release
# - Bump version numbers
# - Update changelog
# - Final bug fixes only (no new features)
git add package.json CHANGELOG.md
git commit -m "chore: bump version to 1.1.0"
git add src/bugfix.ts
git commit -m "fix: resolve minor UI issue"
# 3. Merge release to main
git checkout main
git merge --no-ff release/1.1.0 -m "Release version 1.1.0"
# 4. Tag the release
git tag -a v1.1.0 -m "Release version 1.1.0"
# 5. Merge release back to develop
git checkout develop
git merge --no-ff release/1.1.0 -m "Merge release 1.1.0 back to develop"
# 6. Delete release branch
git branch -d release/1.1.0
# 7. Push everything
git push origin main develop --tagsHotfix Workflow
# 1. Create hotfix branch from main
git checkout -b hotfix/critical-security-issue main
# 2. Fix the issue
git add src/auth/security.ts
git commit -m "fix: resolve critical security vulnerability"
# 3. Merge hotfix to main
git checkout main
git merge --no-ff hotfix/critical-security-issue -m "Hotfix: security issue"
# 4. Tag the hotfix
git tag -a v1.1.1 -m "Hotfix version 1.1.1"
# 5. Merge hotfix back to develop
git checkout develop
git merge --no-ff hotfix/critical-security-issue -m "Merge hotfix 1.1.1 to develop"
# 6. If release branch exists, merge there too
git checkout release/1.2.0
git merge --no-ff hotfix/critical-security-issue
# 7. Delete hotfix branch
git branch -d hotfix/critical-security-issue
# 8. Push everything
git push origin main develop --tagsKey Principles
Branch Discipline:
- Never commit directly to main or develop
- Always use --no-ff (no fast-forward) for merges
- Preserve branch history for audit trails
Release Process:
- Feature freeze when release branch created
- Only bug fixes on release branch
- QA tests release branch thoroughly
- Merge to main only when ready to deploy
Version Tagging:
- Tag all releases on main branch
- Use semantic versioning (v1.2.3)
- Annotated tags with release notes
---
Feature Branching
Overview
Simple workflow for small teams. Feature branches merge to main when complete.
When to Use
- ✅ Team is small (1-5 developers)
- ✅ Simple workflow sufficient
- ✅ No need for complex release management
- ✅ Infrequent deployments acceptable
Workflow
# Create feature branch
git checkout -b feature/new-component main
# Develop and commit
git commit -m "feat: add new component"
# Merge to main
git checkout main
git merge feature/new-component
# Deploy manually
./deploy.sh---
Comparison Matrix
| Aspect | Trunk-Based | GitHub Flow | GitFlow | Feature Branching |
|---|---|---|---|---|
| Complexity | Medium | Low | High | Very Low |
| Branch Lifetime | <1 day | 1-7 days | Varies | 1-14 days |
| Release Frequency | Continuous | Continuous | Scheduled | Manual |
| CI/CD Requirements | High | Medium | Low | Low |
| Team Size | Any | 2-20 | 5-50+ | 1-5 |
| Learning Curve | Medium | Low | High | Low |
| QA Integration | Automated | Automated | Manual cycle | Manual |
| Hotfix Process | Immediate | Fast | Structured | Ad-hoc |
| Best For | High-velocity teams | Web apps | Enterprise | Small projects |
Choosing the Right Strategy
Start Here: GitHub Flow
For most teams, GitHub Flow is the recommended starting point:
- Simple to understand and adopt
- Works well for modern web applications
- Easy to transition to trunk-based later
- Supports continuous deployment
Migrate to Trunk-Based When:
- Team has mature CI/CD practices
- Test coverage is comprehensive
- Feature flags are implemented
- Team is comfortable with Git
Use GitFlow Only If:
- Multiple production versions required
- Formal release schedule needed
- App Store release process (mobile)
- Enterprise change management required
Avoid Feature Branching Unless:
- Team is very small (1-2 developers)
- Project is simple and short-term
- Deployment frequency is low
Migration Strategies
From Feature Branching to GitHub Flow
1. Set up branch protection on main 2. Require pull requests for all changes 3. Add CI/CD checks (tests, linting) 4. Train team on PR process 5. Implement automated deployments
From GitHub Flow to Trunk-Based
1. Reduce branch lifetime (aim for <1 day) 2. Implement feature flags 3. Increase test coverage to 80%+ 4. Set up comprehensive CI/CD 5. Commit directly to main (with short-lived branches)
From GitFlow to GitHub Flow
1. Merge develop into main 2. Delete develop branch 3. Switch to feature branches from main 4. Remove release branch process 5. Implement continuous deployment
Troubleshooting Common Issues
Long-Lived Branches
Problem: Feature branches last weeks or months
Solutions:
- Break features into smaller increments
- Use feature flags to merge incomplete work
- Implement daily rebasing with main
- Set branch lifetime limits (auto-close PRs after 7 days)
Merge Conflicts
Problem: Frequent conflicts when merging
Solutions:
- Reduce branch lifetime
- Rebase frequently with main
- Communicate about overlapping work
- Use CODEOWNERS to prevent overlap
Broken Main Branch
Problem: Main branch fails CI/CD
Solutions:
- Require status checks before merge
- Add pre-push hooks to run tests
- Implement revert-first policy (revert, fix, re-merge)
- Block direct commits to main
Unclear Release State
Problem: Don't know what's in production
Solutions:
- Tag all production releases
- Use semantic versioning
- Maintain CHANGELOG.md
- Track deployments in monitoring tools
Code Review Workflows
Complete guide to pull request templates, branch protection, and code review best practices.
Table of Contents
1. Pull Request Templates 2. Branch Protection Rules 3. Review Best Practices 4. CODEOWNERS Integration 5. Automated Checks
Pull Request Templates
Basic Template
File: .github/PULL_REQUEST_TEMPLATE.md
## Description
<!-- Brief description of changes -->
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactoring (no functional changes)
- [ ] Performance improvement
- [ ] Test updates
## How Has This Been Tested?
<!-- Describe the tests you ran -->
## Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published
## Screenshots (if applicable)
## Related Issues
<!-- Link to related issues: Closes #123, Fixes #456 -->Feature Template
File: .github/PULL_REQUEST_TEMPLATE/feature.md
## Feature Description
<!-- What feature does this PR add? -->
## Motivation
<!-- Why is this feature needed? -->
## Implementation Details
<!-- How was this implemented? -->
### Architecture Changes
<!-- Any architectural changes? -->
### API Changes
<!-- New endpoints, changed responses, etc. -->
### Database Changes
<!-- Migrations, schema changes, etc. -->
## Testing
- [ ] Unit tests added
- [ ] Integration tests added
- [ ] E2E tests added (if applicable)
- [ ] Manual testing completed
### Test Coverage
- Before: X%
- After: Y%
## Documentation
- [ ] API documentation updated
- [ ] README updated
- [ ] Migration guide created (if breaking change)
## Performance Impact
<!-- Any performance considerations? -->
## Security Considerations
<!-- Any security implications? -->
## Screenshots/Videos
<!-- Visual demonstration of feature -->
## Rollout Plan
<!-- How will this be rolled out? -->
## Related Issues
Closes #
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added
- [ ] All tests pass locallyBug Fix Template
File: .github/PULL_REQUEST_TEMPLATE/bugfix.md
## Bug Description
<!-- What bug does this fix? -->
## Root Cause
<!-- What caused the bug? -->
## Solution
<!-- How does this fix the bug? -->
## Reproduction Steps (Before Fix)
1.
2.
3.
## Expected Behavior
<!-- What should happen? -->
## Actual Behavior (Before Fix)
<!-- What was happening? -->
## Testing
- [ ] Bug reproduction verified
- [ ] Fix verified
- [ ] Regression test added
- [ ] Related functionality tested
## Impact
<!-- Who is affected by this bug? -->
## Related Issues
Fixes #
## Checklist
- [ ] Root cause identified and documented
- [ ] Fix verified
- [ ] Regression test added
- [ ] No new warnings introducedUsing Multiple Templates
.github/PULL_REQUEST_TEMPLATE.md (default) .github/PULL_REQUEST_TEMPLATE/feature.md .github/PULL_REQUEST_TEMPLATE/bugfix.md
Select template when creating PR:
https://github.com/org/repo/compare/main...branch?template=feature.md---
Branch Protection Rules
GitHub Settings
Navigate to: Settings → Branches → Branch protection rules → Add rule
Essential Rules for Main Branch
Branch name pattern: main
Require pull request before merging:
- ☑ Require a pull request before merging
- Required number of approvals: 2
- ☑ Dismiss stale pull request approvals when new commits are pushed
- ☑ Require review from Code Owners
- ☑ Restrict who can dismiss pull request reviews
- Select: @org/principal-engineers
Require status checks to pass before merging:
- ☑ Require status checks to pass before merging
- ☑ Require branches to be up to date before merging
- Required status checks:
- Build
- Tests
- Lint
- Security Scan
- TypeScript Check
Require conversation resolution before merging:
- ☑ Require conversation resolution before merging
Require signed commits:
- ☑ Require signed commits
Require linear history:
- ☑ Require linear history (prevents merge commits)
Additional settings:
- ☑ Include administrators (apply rules to admins too)
- ☑ Restrict who can push to matching branches
- Select: (empty - no one can push directly)
- ☑ Allow force pushes: NO
- ☑ Allow deletions: NO
Protection Rules for Develop Branch
Branch name pattern: develop
Settings:
- Required approvals: 1
- Require status checks
- Allow administrators to bypass (for urgent fixes)
Protection Rules for Release Branches
Branch name pattern: release/*
Settings:
- Required approvals: 2
- Require Code Owner review
- Require status checks
- Restrict who can push: @org/release-managers
Status Check Configuration
Required checks:
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
branches: [main, develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run security audit
run: npm audit --audit-level=moderate---
Review Best Practices
For PR Authors
Before Creating PR: 1. Self-review all changes 2. Run tests locally 3. Update documentation 4. Add descriptive PR title and description 5. Link related issues
PR Size:
- Keep PRs small (< 400 lines changed)
- Split large changes into multiple PRs
- Each PR should represent one logical change
PR Description:
- Explain WHY, not just WHAT
- Include screenshots for UI changes
- List breaking changes clearly
- Provide testing instructions
Responding to Feedback:
- Respond to all comments
- Mark conversations as resolved after addressing
- Push fixup commits, squash before merge
- Request re-review after significant changes
For Reviewers
Review Checklist:
- [ ] Code quality and readability
- [ ] Tests cover new functionality
- [ ] Documentation updated
- [ ] No obvious bugs or logic errors
- [ ] Performance considerations addressed
- [ ] Security implications considered
- [ ] Follows project conventions
Providing Feedback:
- Be specific and constructive
- Provide code examples when suggesting changes
- Distinguish between required changes and suggestions
- Acknowledge good code and smart solutions
Comment Tags:
[REQUIRED] - Must be addressed before approval
[SUGGESTION] - Nice to have, not blocking
[QUESTION] - Seeking clarification
[NITPICK] - Minor style issue
[PRAISE] - Acknowledging good workExample Comments:
[REQUIRED] This function could cause a memory leak.
Please add cleanup logic in the useEffect return.
[SUGGESTION] Consider extracting this logic into a
separate hook for reusability.
[QUESTION] Why did we choose this approach over using
the existing utility function?
[PRAISE] Great solution! This is much cleaner than
the previous implementation.---
CODEOWNERS Integration
File Structure
.github/CODEOWNERS:
# Default owners
* @org/engineering
# Frontend
/apps/web/ @org/frontend-team
/libs/ui-components/ @org/design-system-team
# Backend
/apps/api/ @org/backend-team
/libs/database/ @org/backend-team
# Infrastructure
/.github/ @org/devops-team
/infrastructure/ @org/devops-team
/docker/ @org/devops-team
# Security-critical (require multiple approvals)
/libs/auth/ @org/security-team @org/principal-engineers
/apps/*/src/config/secrets* @org/security-team @org/devops-team
# Documentation
/docs/ @org/tech-writers
*.md @org/tech-writers
# Configuration
package.json @org/principal-engineers
tsconfig*.json @org/principal-engineersAuto-Assignment
When PR is created, GitHub automatically: 1. Requests review from code owners 2. Marks code owner review as required (if branch protection enabled) 3. Prevents merge until code owner approves
Multiple Owners
# Require approval from ALL listed teams
/libs/payments/ @org/payments-team @org/security-team
# First matching pattern wins
/libs/shared/ @org/engineering
/libs/shared/security/ @org/security-team---
Automated Checks
GitHub Actions for PR Validation
.github/workflows/pr-validation.yml:
name: PR Validation
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
validate-pr-title:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
requireScope: false
check-pr-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check PR size
run: |
FILES_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | wc -l)
LINES_CHANGED=$(git diff --stat origin/${{ github.base_ref }}...HEAD | tail -1 | awk '{print $4+$6}')
if [ $LINES_CHANGED -gt 500 ]; then
echo "::warning::PR is large ($LINES_CHANGED lines). Consider splitting."
fi
label-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml
check-todos:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check for TODO comments
run: |
if git diff origin/${{ github.base_ref }}...HEAD | grep -i "TODO"; then
echo "::warning::PR contains TODO comments"
fi
require-changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check CHANGELOG updated
run: |
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "CHANGELOG.md"; then
echo "✅ CHANGELOG updated"
else
echo "::warning::Consider updating CHANGELOG.md"
fiAuto-Labeling
.github/labeler.yml:
'frontend':
- apps/web/**/*
- libs/ui-components/**/*
'backend':
- apps/api/**/*
- libs/database/**/*
'infrastructure':
- .github/**/*
- infrastructure/**/*
- docker/**/*
'documentation':
- docs/**/*
- '**/*.md'
'tests':
- '**/*.test.ts'
- '**/*.test.tsx'
- '**/*.spec.ts'
'dependencies':
- package.json
- package-lock.json
- yarn.lockPR Size Labels
.github/workflows/pr-size.yml:
name: PR Size Labeler
on:
pull_request:
types: [opened, synchronize]
jobs:
size-label:
runs-on: ubuntu-latest
steps:
- uses: codelytv/pr-size-labeler@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
xs_label: 'size/xs'
xs_max_size: 10
s_label: 'size/s'
s_max_size: 100
m_label: 'size/m'
m_max_size: 500
l_label: 'size/l'
l_max_size: 1000
xl_label: 'size/xl'
fail_if_xl: 'false'Require Issue Link
.github/workflows/require-issue.yml:
name: Require Issue Link
on:
pull_request:
types: [opened, edited]
jobs:
check-issue-link:
runs-on: ubuntu-latest
steps:
- name: Check for issue reference
run: |
if echo "${{ github.event.pull_request.body }}" | grep -qE "(Closes|Fixes|Refs) #[0-9]+"; then
echo "✅ Issue reference found"
else
echo "::error::PR must reference an issue (Closes #123, Fixes #456, Refs #789)"
exit 1
fi---
Best Practices Summary
PR Creation
Do:
- ✅ Keep PRs small and focused
- ✅ Write descriptive titles (conventional format)
- ✅ Include detailed description
- ✅ Link related issues
- ✅ Add screenshots for UI changes
- ✅ Self-review before requesting review
Don't:
- ❌ Mix unrelated changes
- ❌ Submit large PRs (>500 lines)
- ❌ Leave TODO comments
- ❌ Skip tests
- ❌ Forget documentation
Code Review
Do:
- ✅ Review within 24 hours
- ✅ Provide constructive feedback
- ✅ Test locally for complex changes
- ✅ Approve when ready (don't block unnecessarily)
- ✅ Use comment tags ([REQUIRED], [SUGGESTION])
Don't:
- ❌ Nitpick style issues (use automated tools)
- ❌ Block on personal preferences
- ❌ Leave comments without explanation
- ❌ Approve without reviewing
Branch Protection
Required:
- ✅ Require PR reviews (2+ approvals)
- ✅ Require status checks
- ✅ Require code owner approval
- ✅ Prevent force pushes
- ✅ Require linear history
Optional:
- ⚠️ Require signed commits (if security critical)
- ⚠️ Restrict merge methods (squash only)
- ⚠️ Auto-delete branches after merge
Conventional Commits Specification
Complete guide to conventional commit format for automated versioning and changelog generation.
Table of Contents
1. Specification 2. Commit Types 3. Scopes 4. Breaking Changes 5. Semantic Versioning Integration 6. Tool Setup 7. Examples
Specification
Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Components
Type (required): Category of change Scope (optional): Area of codebase affected Description (required): Short summary (imperative mood) Body (optional): Detailed explanation Footer (optional): Breaking changes, issue references
Rules
1. Type and description are mandatory 2. Type must be lowercase 3. Description must be lowercase (no capitalization) 4. No period at end of description 5. Body separated by blank line 6. Footer separated by blank line 7. Line length: header ≤100 chars, body ≤72 chars
---
Commit Types
Core Types
| Type | Description | Changelog | SemVer Impact |
|---|---|---|---|
feat | New feature | ✅ Yes | MINOR (0.1.0) |
fix | Bug fix | ✅ Yes | PATCH (0.0.1) |
docs | Documentation only | ❌ No | - |
style | Formatting, whitespace | ❌ No | - |
refactor | Code change (no feature/fix) | ❌ No | - |
perf | Performance improvement | ✅ Yes | PATCH (0.0.1) |
test | Adding or updating tests | ❌ No | - |
build | Build system changes | ❌ No | - |
ci | CI configuration changes | ❌ No | - |
chore | Maintenance tasks | ❌ No | - |
revert | Revert previous commit | ✅ Yes | Context-dependent |
Type Guidelines
feat (Feature)
New functionality visible to users:
feat: add user registration
feat(auth): add password reset flow
feat(api): add pagination to user endpointNot a feature:
- Internal refactoring
- Test improvements
- Build changes
fix (Bug Fix)
Fixes user-facing bug:
fix: resolve login redirect loop
fix(ui): correct button alignment on mobile
fix(api): handle null values in responseNot a fix:
- Fixing tests
- Fixing CI
- Code cleanup
docs (Documentation)
Documentation changes only:
docs: update installation instructions
docs(api): add authentication examples
docs: fix typo in READMEScope:
- README updates
- API documentation
- Code comments
- Migration guides
style (Code Style)
Formatting changes (no logic change):
style: format code with prettier
style: fix indentation in user controller
style: remove trailing whitespaceExamples:
- Prettier/ESLint formatting
- Import order changes
- Whitespace cleanup
refactor (Code Refactoring)
Code restructuring without feature/fix:
refactor: extract user validation logic
refactor(auth): simplify token generation
refactor: rename variables for clarityNot a refactor:
- Adding new functionality →
feat - Fixing bugs →
fix
perf (Performance)
Performance improvements:
perf: reduce database query time by 50%
perf(api): add caching to user endpoint
perf: optimize image loadingtest (Tests)
Adding or updating tests:
test: add unit tests for user service
test(auth): add integration tests
test: increase coverage to 80%build (Build System)
Changes to build configuration:
build: upgrade webpack to v5
build: add source maps to production build
build(deps): update dependenciesExamples:
- Webpack configuration
- Babel configuration
- Package.json scripts
ci (Continuous Integration)
CI configuration changes:
ci: add GitHub Actions workflow
ci: increase test timeout
ci: add caching to CI pipelineExamples:
- GitHub Actions
- Jenkins
- CircleCI
- GitLab CI
chore (Maintenance)
Maintenance tasks:
chore: update .gitignore
chore: bump version to 1.2.0
chore(deps): update dev dependenciesrevert (Revert Commit)
Reverting previous commit:
revert: feat(auth): add social login
This reverts commit a1b2c3d4e5f6.---
Scopes
Purpose
Scopes indicate which part of codebase is affected. Use when repository has clear module boundaries.
Format
<type>(<scope>): <description>Common Scopes
By Module:
feat(auth): add JWT validation
fix(api): resolve timeout issue
test(database): add migration testsBy Layer:
feat(frontend): add user dashboard
fix(backend): resolve memory leak
docs(infrastructure): update deployment guideBy Feature:
feat(notifications): add email notifications
fix(payments): resolve Stripe integration
refactor(analytics): simplify event trackingScope Examples by Project Type
Web Application:
ui,api,auth,database,cache
Library:
core,utils,types,validation
Monorepo:
web,mobile,shared,api,admin
Multiple Scopes
Use comma separation for changes affecting multiple areas:
refactor(api,database): migrate to PostgreSQLOr omit scope if change is global:
refactor: migrate to PostgreSQL---
Breaking Changes
Format
Add ! after type/scope:
feat!: redesign authentication API
feat(api)!: change user endpoint response formatAnd/or add BREAKING CHANGE: in footer:
feat(api): redesign authentication endpoints
BREAKING CHANGE: Auth endpoints now require API version header.
Migration guide: https://docs.example.com/v2-migrationWhen to Use
Mark as breaking change when:
- API contract changes
- Function signature changes
- Configuration format changes
- Database schema migrations required
- Behavior change affects existing users
Examples
API Change:
feat(api)!: change user response format
BREAKING CHANGE: User API now returns nested objects.
Before:
{
"id": 1,
"name": "John",
"email": "john@example.com"
}
After:
{
"id": 1,
"profile": {
"name": "John",
"email": "john@example.com"
}
}Configuration Change:
refactor(config)!: change configuration file format
BREAKING CHANGE: Configuration now uses YAML instead of JSON.
Rename config.json to config.yml and update syntax.Function Signature:
feat(auth)!: change login function signature
BREAKING CHANGE: login() now returns Promise instead of callback.
Before: login(credentials, callback)
After: await login(credentials)---
Semantic Versioning Integration
Version Format
MAJOR.MINOR.PATCH (e.g., 2.1.3)
Version Bumping
| Commit Type | Version Bump | Example |
|---|---|---|
feat: | MINOR | 1.2.0 → 1.3.0 |
fix: | PATCH | 1.2.0 → 1.2.1 |
perf: | PATCH | 1.2.0 → 1.2.1 |
feat!: or BREAKING CHANGE: | MAJOR | 1.2.0 → 2.0.0 |
Pre-1.0.0 Versions
Before 1.0.0, breaking changes bump MINOR:
0.2.0 → 0.3.0 (breaking change)
0.2.0 → 0.2.1 (fix)Examples
Patch Release (1.2.0 → 1.2.1):
fix: resolve login timeout
fix(api): handle null responses
perf: optimize database queriesMinor Release (1.2.0 → 1.3.0):
feat: add dark mode
feat(notifications): add email notifications
fix: resolve various bugsMajor Release (1.2.0 → 2.0.0):
feat!: redesign API
BREAKING CHANGE: API v1 endpoints removed---
Tool Setup
Commitlint Installation
# Install commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Create configuration file
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.jsCommitlint Configuration
commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// Type enumeration
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert'
]],
// Subject case (lowercase)
'subject-case': [2, 'never', ['upper-case', 'pascal-case', 'start-case']],
// Header max length
'header-max-length': [2, 'always', 100],
// Body max line length
'body-max-line-length': [2, 'always', 72],
// Scope case (lowercase)
'scope-case': [2, 'always', 'lower-case'],
// Empty subject not allowed
'subject-empty': [2, 'never'],
// Subject must not end with period
'subject-full-stop': [2, 'never', '.']
}
};Husky Integration
# Install Husky
npm install --save-dev husky
npx husky init
# Add commit-msg hook
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'.husky/commit-msg:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit $1Validation Examples
Valid commits:
git commit -m "feat: add user registration"
✅ PASS
git commit -m "fix(auth): resolve login timeout"
✅ PASS
git commit -m "feat!: redesign API"
✅ PASSInvalid commits:
git commit -m "Add user registration"
❌ FAIL: type missing
git commit -m "FEAT: add registration"
❌ FAIL: type must be lowercase
git commit -m "feat add registration"
❌ FAIL: missing colon
git commit -m "feat: Add registration"
❌ FAIL: description must be lowercase---
Semantic Release Setup
Installation
npm install --save-dev semantic-release \
@semantic-release/commit-analyzer \
@semantic-release/release-notes-generator \
@semantic-release/changelog \
@semantic-release/npm \
@semantic-release/git \
@semantic-release/githubConfiguration
.releaserc.json:
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
[
"@semantic-release/git",
{
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
"@semantic-release/github"
]
}GitHub Actions Workflow
.github/workflows/release.yml:
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Test
run: npm test
- name: Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-releaseAutomated Changelog
Semantic Release generates CHANGELOG.md automatically:
# Changelog
## [2.0.0](https://github.com/org/repo/compare/v1.2.3...v2.0.0) (2025-12-04)
### ⚠ BREAKING CHANGES
* **api**: Auth endpoints now require API version header
### Features
* **auth**: add JWT token validation ([a1b2c3d](link))
* **api**: add user profile endpoints ([e4f5g6h](link))
### Bug Fixes
* **ui**: resolve button alignment issue ([i7j8k9l](link))
* resolve race condition in login ([m0n1o2p](link))---
Examples
Simple Feature
git commit -m "feat: add dark mode toggle"Feature with Scope
git commit -m "feat(ui): add dark mode toggle to settings"Bug Fix
git commit -m "fix: resolve memory leak in event listeners"Bug Fix with Scope and Body
git commit -m "fix(auth): resolve token expiration issue
Token expiration was not being checked correctly, causing users
to remain logged in after token expired. Added proper validation
and automatic logout when token expires.
Fixes #123"Breaking Change (Short Form)
git commit -m "feat(api)!: change user endpoint response format"Breaking Change (Full Form)
git commit -m "feat(api): redesign authentication endpoints
Redesigned authentication endpoints for better security and
performance. New endpoints use JWT tokens instead of sessions.
BREAKING CHANGE: Auth endpoints now require API version header.
Migration guide:
1. Add 'X-API-Version: 2' header to all API requests
2. Update client libraries to latest version
3. Clear browser cookies
Closes #456"Multiple Types in One Commit
If commit contains multiple changes, use the primary type:
# Fix is primary, docs are secondary
git commit -m "fix(api): resolve timeout issue
Also updated API documentation to reflect new timeout values.
Fixes #789"Or split into multiple commits (preferred):
git commit -m "fix(api): resolve timeout issue"
git commit -m "docs(api): update timeout documentation"Revert Commit
git commit -m "revert: feat(auth): add social login
This reverts commit a1b2c3d4e5f6.
Social login feature caused authentication issues in production.
Reverting to investigate and fix before re-deploying."Monorepo Scopes
git commit -m "feat(web): add user dashboard"
git commit -m "fix(mobile): resolve crash on startup"
git commit -m "refactor(shared): extract common utilities"
git commit -m "test(api): add integration tests"Best Practices
Commit Frequency
Good: Small, focused commits
git commit -m "feat(auth): add login form"
git commit -m "feat(auth): add password validation"
git commit -m "test(auth): add login form tests"Avoid: Large, unfocused commits
git commit -m "feat: add authentication and user profile and settings"Description Quality
Good: Clear, specific descriptions
git commit -m "fix(api): resolve race condition in user creation"
git commit -m "perf(database): add index to user_id column"
git commit -m "feat(notifications): add email notification support"Avoid: Vague descriptions
git commit -m "fix: fix bug"
git commit -m "feat: add stuff"
git commit -m "refactor: update code"Body Usage
Use body for complex changes:
git commit -m "refactor(database): migrate from MySQL to PostgreSQL
- Migrate all table schemas to PostgreSQL syntax
- Update ORM configuration
- Add migration scripts for existing data
- Update backup procedures
This migration improves performance and adds support for
advanced query features needed for analytics.
Refs: #123, #456"Footer Usage
Issue References:
Fixes #123
Closes #456
Refs #789Breaking Changes:
BREAKING CHANGE: Configuration file format changed from JSON to YAMLCo-authors:
Co-authored-by: John Doe <john@example.com>
Co-authored-by: Jane Smith <jane@example.com>Git Hooks Guide
Complete guide to Git hooks for quality gates, including setup, configuration, and examples.
Table of Contents
1. Hook Types 2. Husky Setup 3. Lint-Staged Configuration 4. Commitlint Setup 5. Pre-Push Hooks 6. Complete Setup Example 7. Troubleshooting
Hook Types
Client-Side Hooks
| Hook | Trigger | Common Use Cases |
|---|---|---|
pre-commit | Before commit created | Linting, formatting, quick tests |
prepare-commit-msg | After default message | Add issue number, template |
commit-msg | After message written | Validate format, enforce conventions |
post-commit | After commit created | Notifications, logging |
pre-push | Before push to remote | Run tests, prevent force push |
pre-rebase | Before rebase | Prevent rebasing protected branches |
Server-Side Hooks
| Hook | Trigger | Common Use Cases |
|---|---|---|
pre-receive | Before refs updated | Enforce policies, run checks |
update | Before each ref updated | Per-branch policies |
post-receive | After refs updated | Deploy, notify, CI trigger |
---
Husky Setup
Installation
# Install Husky
npm install --save-dev husky
# Initialize Husky
npx husky init
# This creates:
# - .husky/ directory
# - .husky/pre-commit hook (example)
# - Updates package.json with "prepare" scriptpackage.json:
{
"scripts": {
"prepare": "husky install"
},
"devDependencies": {
"husky": "^8.0.3"
}
}Adding Hooks
# Add pre-commit hook
npx husky add .husky/pre-commit "npm run lint"
# Add commit-msg hook
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
# Add pre-push hook
npx husky add .husky/pre-push "npm test"Hook File Structure
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
npm run formatMake hooks executable:
chmod +x .husky/pre-commit
chmod +x .husky/commit-msg
chmod +x .husky/pre-push---
Lint-Staged Configuration
Purpose
Run linters only on staged files for performance. Avoids linting entire codebase on every commit.
Installation
npm install --save-dev lint-stagedConfiguration
package.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,yml,yaml}": [
"prettier --write"
],
"*.css": [
"stylelint --fix",
"prettier --write"
]
}
}Or .lintstagedrc.json:
{
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,yml,yaml}": [
"prettier --write"
],
"*.css": [
"stylelint --fix",
"prettier --write"
]
}Pre-Commit Hook with Lint-Staged
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-stagedAdvanced Configuration
Run tests on changed files:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write",
"jest --bail --findRelatedTests"
]
}
}Different commands for different directories:
{
"lint-staged": {
"apps/web/**/*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"apps/api/**/*.ts": [
"eslint --fix",
"prettier --write",
"jest --findRelatedTests"
],
"packages/**/*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}---
Commitlint Setup
Installation
npm install --save-dev @commitlint/cli @commitlint/config-conventionalConfiguration
commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert'
]
],
'subject-case': [2, 'never', ['upper-case', 'pascal-case', 'start-case']],
'header-max-length': [2, 'always', 100],
'body-max-line-length': [2, 'always', 72],
'scope-case': [2, 'always', 'lower-case']
}
};Custom Rules
Allow custom types:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert',
'wip', // Work in progress
'hotfix' // Hot fixes
]
]
}
};Enforce scopes:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-enum': [
2,
'always',
['api', 'ui', 'auth', 'database', 'docs']
],
'scope-empty': [2, 'never'] // Scope required
}
};Commit-Msg Hook
.husky/commit-msg:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit $1Testing Commit Messages
# Test a commit message
echo "feat: add user registration" | npx commitlint
# Test from file
echo "fix(api): resolve timeout" > /tmp/commit.txt
npx commitlint --edit /tmp/commit.txt---
Pre-Push Hooks
Run Tests Before Push
.husky/pre-push:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run test suite
npm run test:ci
# Exit if tests fail
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Push aborted."
exit 1
fiPrevent Force Push to Main
.husky/pre-push:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Get current branch name
branch=$(git rev-parse --abbrev-ref HEAD)
# Check if force pushing to main
if [ "$branch" = "main" ] && git push --dry-run --force 2>&1 | grep -q "force"; then
echo "⛔ Force push to main branch is not allowed!"
exit 1
fi
# Run tests
npm run test:ciRun Only Affected Tests
.husky/pre-push:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Get list of changed files
changed_files=$(git diff --name-only origin/main...HEAD)
# Run tests for changed files
npm run test -- --findRelatedTests $changed_filesBuild Before Push
.husky/pre-push:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run build
npm run build
if [ $? -ne 0 ]; then
echo "❌ Build failed. Push aborted."
exit 1
fi
echo "✅ Build successful. Continuing with push."---
Complete Setup Example
Full Package Configuration
package.json:
{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"prepare": "husky install",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "jest",
"test:ci": "jest --coverage --maxWorkers=2",
"test:changed": "jest --bail --findRelatedTests",
"build": "tsc && vite build"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write",
"jest --bail --findRelatedTests"
],
"*.{json,md,yml,yaml}": [
"prettier --write"
]
},
"devDependencies": {
"husky": "^8.0.3",
"lint-staged": "^15.0.0",
"@commitlint/cli": "^18.0.0",
"@commitlint/config-conventional": "^18.0.0",
"eslint": "^8.50.0",
"prettier": "^3.0.0",
"jest": "^29.7.0",
"typescript": "^5.2.0"
}
}Husky Hooks
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run lint-staged (linting + formatting + tests for staged files)
npx lint-staged
# Check for console.log in staged files
if git diff --cached | grep -E "^\+.*console\.log"; then
echo "⚠️ Warning: console.log found in staged files"
echo "Remove console.log or use --no-verify to skip this check"
exit 1
fi.husky/commit-msg:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Validate commit message format
npx --no -- commitlint --edit $1.husky/pre-push:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Get current branch
branch=$(git rev-parse --abbrev-ref HEAD)
# Prevent force push to main
if [ "$branch" = "main" ]; then
echo "⛔ Cannot push to main branch directly"
echo "Please create a pull request instead"
exit 1
fi
# Run full test suite
echo "Running tests before push..."
npm run test:ci
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Push aborted."
exit 1
fi
# Run build
echo "Building project..."
npm run build
if [ $? -ne 0 ]; then
echo "❌ Build failed. Push aborted."
exit 1
fi
echo "✅ All checks passed. Pushing to remote..."Commitlint Configuration
commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert'
]
],
'subject-case': [2, 'never', ['upper-case', 'pascal-case', 'start-case']],
'header-max-length': [2, 'always', 100],
'body-max-line-length': [2, 'always', 72],
'scope-case': [2, 'always', 'lower-case'],
'scope-enum': [
2,
'always',
['api', 'ui', 'auth', 'database', 'docs', 'infra', 'tests']
]
}
};---
Advanced Patterns
Conditional Hooks
Run hooks only for specific branches:
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
branch=$(git rev-parse --abbrev-ref HEAD)
# Only run on non-main branches
if [ "$branch" != "main" ]; then
npx lint-staged
fiSkip Hooks When Needed
# Skip pre-commit hook
git commit --no-verify -m "fix: urgent hotfix"
# Skip pre-push hook
git push --no-verify⚠️ Use sparingly: Only for urgent fixes or when absolutely necessary.
Shared Hooks in Monorepo
Root .husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run lint-staged in each workspace
npx lerna run --concurrency 1 --stream lint-stagedPerformance Optimization
Run only necessary checks:
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Quick checks only (no tests)
npx lint-staged --config .lintstagedrc.quick.json.lintstagedrc.quick.json:
{
"*.{js,jsx,ts,tsx}": [
"eslint --fix --max-warnings=0",
"prettier --write"
]
}---
Troubleshooting
Hooks Not Running
Problem: Hooks don't execute on commit/push
Solutions:
# Reinstall Husky
rm -rf .husky
npx husky init
# Make hooks executable
chmod +x .husky/pre-commit
chmod +x .husky/commit-msg
chmod +x .husky/pre-push
# Verify Git hooks directory
git config core.hooksPath
# Should output: .huskySlow Pre-Commit Hook
Problem: Pre-commit takes too long
Solutions:
- Use lint-staged (only check staged files)
- Remove expensive operations (full test suite)
- Run quick checks only (linting, formatting)
- Move slow checks to pre-push or CI
# Before (slow)
npm run lint # Lints entire codebase
npm run test # Runs all tests
# After (fast)
npx lint-staged # Only staged filesCommitlint Fails Unexpectedly
Problem: Valid commits are rejected
Solutions:
# Test commit message
echo "feat: add feature" | npx commitlint
# Check configuration
cat commitlint.config.js
# Use verbose mode
npx commitlint --verbose
# Verify installed version
npx commitlint --versionWindows Line Endings
Problem: Hooks fail on Windows (CRLF vs LF)
Solutions:
# Configure Git to handle line endings
git config core.autocrlf false
# Convert existing hooks to LF
dos2unix .husky/*
# Or use .gitattributes
echo "* text=auto eol=lf" >> .gitattributes
echo ".husky/** text eol=lf" >> .gitattributesHook Fails in CI/CD
Problem: Hooks run in CI when they shouldn't
Solutions:
# Skip Husky in CI
CI=true npm ci # Husky won't install
# Or in package.json
{
"scripts": {
"prepare": "husky install || true"
}
}
# Or use postinstall for development only
{
"scripts": {
"postinstall": "is-ci || husky install"
}
}Bypass Hooks for Urgent Fixes
# Skip all hooks
git commit --no-verify -m "fix: urgent production hotfix"
git push --no-verify
# Better: Fix and commit properly after
git commit --amend --no-edit
# (hooks will run on amend)---
Best Practices
Pre-Commit Checks
Do:
- ✅ Linting and formatting (fast)
- ✅ Quick static analysis
- ✅ Check for sensitive data (secrets, API keys)
Don't:
- ❌ Full test suite (too slow)
- ❌ Build entire project
- ❌ Network requests
Pre-Push Checks
Do:
- ✅ Run test suite
- ✅ Build project
- ✅ Check branch protection
Don't:
- ❌ Deploy to production
- ❌ Modify remote repository
Hook Performance
Keep hooks fast:
- Pre-commit: <5 seconds
- Commit-msg: <1 second
- Pre-push: <30 seconds
Team Setup
Document hook requirements:
# Development Setup
1. Install dependencies: `npm install`
2. Git hooks are automatically installed via Husky
3. Pre-commit runs linting and formatting
4. Commit messages must follow conventional format
5. Pre-push runs tests and builds project
To skip hooks (emergency only): `git commit --no-verify`Debugging Hooks
Add debug output:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "🔍 Running pre-commit hook..."
echo "Branch: $(git rev-parse --abbrev-ref HEAD)"
echo "Staged files:"
git diff --cached --name-only
npx lint-stagedMonorepo Management Patterns
Complete guide to managing monorepos with build tools, Git strategies, and code ownership patterns.
Table of Contents
1. Monorepo vs Polyrepo 2. Build Tool Selection 3. Nx Configuration 4. Turborepo Configuration 5. Git Sparse Checkout 6. CODEOWNERS Setup 7. Submodules vs Subtrees
Monorepo vs Polyrepo
Monorepo Benefits
Code Management:
- ✅ Atomic commits across multiple projects
- ✅ Easier refactoring (see all usage)
- ✅ Single source of truth
- ✅ Shared tooling and configuration
Development Workflow:
- ✅ Simplified dependency management
- ✅ Consistent versioning
- ✅ Better code reuse
- ✅ Easier to onboard new developers
Build and Deploy:
- ✅ Coordinated releases
- ✅ Shared CI/CD configuration
- ✅ Faster iteration on shared libraries
Monorepo Challenges
Performance:
- ❌ Large repository size
- ❌ Slower Git operations (clone, checkout, status)
- ❌ IDE indexing takes longer
- ❌ CI/CD complexity increases
Organization:
- ❌ Code ownership ambiguity
- ❌ More complex CI/CD
- ❌ Access control harder to manage
- ❌ Risk of tight coupling
When to Use Monorepo
Use monorepo when:
- Multiple projects share significant code
- Team owns all projects
- Atomic changes across projects needed
- Shared tooling and standards important
Use polyrepo when:
- Projects are independent
- Different teams own projects
- Different release cycles
- Independent scalability needed
---
Build Tool Selection
Comparison Matrix
| Feature | Nx | Turborepo | Lerna |
|---|---|---|---|
| Language | TypeScript/JS | Any | TypeScript/JS |
| Dependency Graph | ✅ Advanced | ✅ Basic | ❌ No |
| Affected Commands | ✅ Yes | ✅ Yes | ❌ No |
| Caching | ✅ Local + Remote | ✅ Local + Remote | ❌ No |
| Incremental Builds | ✅ Yes | ✅ Yes | ❌ No |
| IDE Integration | ✅ Excellent | ⚠️ Limited | ❌ No |
| Learning Curve | Medium | Low | Low |
| Best For | Large TS/JS monorepos | Next.js/React apps | Legacy projects |
Recommendation
Choose Nx when:
- Large TypeScript/JavaScript monorepo
- Need advanced dependency analysis
- Want IDE integration (VS Code extension)
- Team is experienced with build tools
Choose Turborepo when:
- Next.js or React applications
- Want simple, fast setup
- Need remote caching (Vercel)
- Prefer minimal configuration
Choose Lerna when:
- Maintaining existing Lerna project
- Simple publishing workflow
- (Note: Consider migrating to Nx or Turborepo)
---
Nx Configuration
Installation
# Create new Nx workspace
npx create-nx-workspace@latest myworkspace
# Options:
# - Select preset: "apps" or "ts"
# - Package manager: npm, yarn, or pnpmProject Structure
monorepo/
├── apps/
│ ├── web-app/ # Frontend application
│ ├── mobile-app/ # Mobile application
│ └── admin-dashboard/ # Admin application
├── libs/
│ ├── ui-components/ # Shared UI components
│ ├── auth/ # Authentication library
│ ├── api-client/ # API client library
│ └── shared-utils/ # Utility functions
├── tools/
│ └── generators/ # Custom generators
├── nx.json # Nx configuration
├── package.json
└── tsconfig.base.jsonNx Configuration
nx.json:
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test", "lint"],
"parallel": 3
}
}
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"outputs": ["{projectRoot}/dist"]
},
"test": {
"inputs": ["default", "^production"]
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"production": [
"!{projectRoot}/**/*.spec.ts",
"!{projectRoot}/tsconfig.spec.json"
]
}
}Common Nx Commands
# Run build for specific project
nx build web-app
# Run build for all affected projects
nx affected:build --base=main
# Run tests for all affected projects
nx affected:test --base=main
# Run lint for all affected projects
nx affected:lint --base=main
# Show dependency graph
nx graph
# Run all builds in parallel
nx run-many --target=build --all
# Reset Nx cache
nx resetProject Configuration
apps/web-app/project.json:
{
"name": "web-app",
"sourceRoot": "apps/web-app/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/web-app",
"main": "apps/web-app/src/main.tsx",
"tsConfig": "apps/web-app/tsconfig.app.json"
}
},
"serve": {
"executor": "@nx/webpack:dev-server",
"options": {
"buildTarget": "web-app:build",
"port": 3000
}
},
"test": {
"executor": "@nx/jest:jest",
"options": {
"jestConfig": "apps/web-app/jest.config.ts"
}
}
}
}Nx Affected Commands
Run only what changed:
# Build only affected projects since main
nx affected:build --base=main --head=HEAD
# Test only affected projects
nx affected:test --base=main
# Lint only affected projects
nx affected:lint --base=main
# Run all affected targets
nx affected --target=build,test,lint --base=mainNx Caching
Local Cache: Automatically caches build outputs locally:
# First build (no cache)
nx build web-app # Takes 30s
# Second build (cached)
nx build web-app # Takes <1sRemote Cache (Nx Cloud):
# Connect to Nx Cloud
npx nx connect-to-nx-cloud
# Shared cache across team
nx build web-app # Downloads from cache if built by teammate---
Turborepo Configuration
Installation
# Create new Turborepo
npx create-turbo@latest
# Project structure will be createdProject Structure
monorepo/
├── apps/
│ ├── web/ # Next.js app
│ │ ├── package.json
│ │ └── src/
│ └── docs/ # Documentation site
│ ├── package.json
│ └── src/
├── packages/
│ ├── ui/ # UI component library
│ │ ├── package.json
│ │ └── src/
│ ├── eslint-config-custom/ # Shared ESLint config
│ └── tsconfig/ # Shared TypeScript config
├── turbo.json # Turborepo configuration
├── package.json # Root package.json
└── pnpm-workspace.yaml # Workspace config (if using pnpm)Turborepo Configuration
turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "build/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": false
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}Common Turborepo Commands
# Run build for all projects
turbo run build
# Run build for specific project
turbo run build --filter=web
# Run dev for all apps
turbo run dev
# Run tests
turbo run test
# Clear cache
turbo run build --forceWorkspace Configuration
package.json (root):
{
"name": "monorepo",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "^1.10.0"
}
}pnpm-workspace.yaml:
packages:
- 'apps/*'
- 'packages/*'Package Dependencies
apps/web/package.json:
{
"name": "web",
"dependencies": {
"ui": "*",
"next": "^14.0.0",
"react": "^18.2.0"
},
"devDependencies": {
"eslint-config-custom": "*",
"tsconfig": "*"
}
}packages/ui/package.json:
{
"name": "ui",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
}
}Remote Caching
Enable Vercel Remote Cache:
# Login to Vercel
npx turbo login
# Link project
npx turbo link
# Builds now use remote cache
turbo run build---
Git Sparse Checkout
Overview
Clone only needed directories from large monorepo.
Enable Sparse Checkout
# Clone without checking out files
git clone --no-checkout https://github.com/org/monorepo.git
cd monorepo
# Enable sparse checkout
git sparse-checkout init --cone
# Checkout only specific directories
git sparse-checkout set apps/web libs/ui-components
# Now checkout files
git checkout mainVerify Sparse Checkout
# List current sparse checkout
git sparse-checkout list
# Output:
# apps/web
# libs/ui-componentsAdd More Directories
# Add additional directories
git sparse-checkout add libs/auth libs/api-client
# List again
git sparse-checkout listDisable Sparse Checkout
# Get full repository
git sparse-checkout disablePerformance Benefits
Before (full checkout):
# Clone full repo: 2.5 GB, 50,000 files
git clone https://github.com/org/monorepo.git # 5 minutes
git status # 10 secondsAfter (sparse checkout):
# Clone sparse: 500 MB, 10,000 files
git sparse-checkout set apps/web # 1 minute
git status # 1 second---
CODEOWNERS Setup
File Location
Create .github/CODEOWNERS in repository root.
Syntax
# Pattern Owner(s)
# Default owner for everything
* @org/engineering
# Apps ownership
/apps/web/ @org/web-team
/apps/mobile/ @org/mobile-team
/apps/admin/ @org/admin-team
# Libraries ownership
/libs/ui-components/ @org/design-system-team
/libs/auth/ @org/security-team
/libs/api-client/ @org/web-team @org/mobile-team
# Infrastructure and CI
/.github/ @org/devops-team
/infrastructure/ @org/devops-team
/docker/ @org/devops-team
# Documentation
/docs/ @org/tech-writers
*.md @org/tech-writers
# Configuration files
package.json @org/principal-engineers
tsconfig*.json @org/principal-engineers
# Security-critical (require multiple approvals)
/libs/auth/ @org/security-team @org/principal-engineers
/apps/*/src/config/secrets* @org/security-team @org/devops-teamPattern Examples
# Match all files
*
# Match directory
/apps/web/
# Match file extension
*.ts
# Match files in any directory
**/*.md
# Match specific file
/package.json
# Match nested directory
/apps/web/src/components/Multiple Owners
# Require approval from both teams
/libs/payments/ @org/payments-team @org/security-team
# Either team can approve
/docs/ @org/tech-writers @org/engineeringTeam Structure
GitHub Organization Teams:
org/
├── engineering
├── web-team
├── mobile-team
├── security-team
├── devops-team
├── design-system-team
└── principal-engineersBranch Protection
Enforce CODEOWNERS:
Settings → Branches → Branch protection rules → main
☑ Require pull request reviews before merging
☑ Require review from Code OwnersTesting CODEOWNERS
# GitHub CLI
gh pr create
# View required reviewers
gh pr view
# Request review from code owners
gh pr review --request @org/web-team---
Submodules vs Subtrees
Git Submodules
When to Use
Use submodules when:
- ✅ External dependencies you don't control
- ✅ Need strict version pinning
- ✅ Subproject developed separately
Setup
# Add submodule
git submodule add https://github.com/org/shared-lib libs/shared
# Clone repo with submodules
git clone --recurse-submodules https://github.com/org/main-repo
# Initialize submodules in existing repo
git submodule init
git submodule update
# Update submodules to latest
git submodule update --remote
# Update specific submodule
git submodule update --remote libs/sharedWorkflow
# Make changes in submodule
cd libs/shared
git checkout main
git pull
cd ../..
git add libs/shared
git commit -m "chore: update shared library"
# Push submodule changes
cd libs/shared
git push origin main
cd ../..
git push origin mainRemove Submodule
# Deinitialize
git submodule deinit libs/shared
# Remove from Git
git rm libs/shared
# Remove from .git/config
rm -rf .git/modules/libs/sharedGit Subtrees
When to Use
Use subtrees when:
- ✅ Want simpler workflow than submodules
- ✅ Need entire history in parent repo
- ✅ Contributors unfamiliar with submodules
Setup
# Add subtree
git subtree add --prefix libs/shared https://github.com/org/shared-lib main --squash
# Pull updates
git subtree pull --prefix libs/shared https://github.com/org/shared-lib main --squash
# Push changes back
git subtree push --prefix libs/shared https://github.com/org/shared-lib mainWorkflow
# Make changes to subtree
cd libs/shared
# Edit files
cd ../..
git add libs/shared
git commit -m "feat(shared): add new utility"
# Push changes to subtree repo
git subtree push --prefix libs/shared https://github.com/org/shared-lib main
# Pull updates from subtree
git subtree pull --prefix libs/shared https://github.com/org/shared-lib main --squashComparison
| Feature | Submodules | Subtrees |
|---|---|---|
| Clone Complexity | Requires --recurse-submodules | Normal clone works |
| History | Separate history | Merged history |
| Learning Curve | High | Medium |
| Updates | Explicit (git submodule update) | Pull/push commands |
| CI/CD | More complex | Simpler |
| Best For | External dependencies | Internal shared code |
Recommendation
Avoid both when possible:
- Use package manager (npm, yarn) for shared libraries
- Use monorepo build tools (Nx, Turborepo)
- Use workspace features (npm workspaces, yarn workspaces)
Use submodules only for:
- External dependencies
- Strict version control needed
Use subtrees only for:
- Vendoring dependencies
- One-way code sharing
---
Best Practices
Git Workflow
Frequent Commits:
# Commit changes to multiple projects atomically
git add apps/web apps/mobile libs/shared
git commit -m "feat: add new authentication flow"Branch Naming:
# Include affected projects
feature/web-mobile-auth-flow
bugfix/api-timeout-issue
refactor/shared-utils-cleanupPR Size:
- Keep PRs small (< 500 lines)
- Split large changes across multiple PRs
- Group related changes together
Code Organization
Shared Code:
libs/
├── ui-components/ # Shared UI components
├── utils/ # Utility functions
├── types/ # TypeScript types
└── config/ # ConfigurationApps:
apps/
├── web/ # Web application
├── mobile/ # Mobile application
└── admin/ # Admin dashboardDependency Management
Use Workspace Protocol:
{
"dependencies": {
"ui-components": "workspace:*",
"shared-utils": "workspace:*"
}
}Version Pinning:
{
"dependencies": {
"react": "18.2.0",
"next": "14.0.0"
}
}CI/CD Optimization
Run Only Affected:
# GitHub Actions
- name: Build affected
run: nx affected:build --base=origin/main
- name: Test affected
run: nx affected:test --base=origin/mainCache Dependencies:
- uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}Performance Tips
Use Sparse Checkout: For large repos, only checkout needed directories.
Enable Caching: Use Nx Cloud or Turbo Remote Cache.
Parallel Execution:
# Nx
nx run-many --target=build --all --parallel=3
# Turborepo
turbo run build --concurrency=3Prune Dependencies:
# Remove unused dependencies
npm prune
# Or with pnpm
pnpm prune#!/bin/bash
# Validate Branch Name Convention
# Enforces branch naming pattern: <type>/<description>
set -e
# Get branch name
if [ -n "$1" ]; then
BRANCH_NAME="$1"
else
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
fi
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Valid branch types
VALID_TYPES="feature|bugfix|hotfix|release|docs|refactor|test|chore"
# Branch name pattern
# Format: <type>/<description-with-hyphens>
PATTERN="^(${VALID_TYPES})/[a-z0-9-]+$"
# Protected branches that don't need to follow pattern
PROTECTED_BRANCHES="main|develop|master|staging|production"
# Validation functions
is_protected_branch() {
if echo "$BRANCH_NAME" | grep -qE "^(${PROTECTED_BRANCHES})$"; then
return 0
fi
return 1
}
validate_format() {
if ! echo "$BRANCH_NAME" | grep -qE "$PATTERN"; then
return 1
fi
return 0
}
validate_type() {
TYPE=$(echo "$BRANCH_NAME" | sed -E 's/^([a-z]+)\/.*/\1/')
if ! echo "$TYPE" | grep -qE "^(${VALID_TYPES})$"; then
echo -e "${RED}❌ Invalid branch type: '$TYPE'${NC}"
echo ""
echo "Valid types:"
echo " feature - New features"
echo " bugfix - Bug fixes"
echo " hotfix - Urgent production fixes"
echo " release - Release preparation"
echo " docs - Documentation changes"
echo " refactor - Code refactoring"
echo " test - Test updates"
echo " chore - Maintenance tasks"
return 1
fi
return 0
}
validate_description() {
# Extract description (after slash)
if ! echo "$BRANCH_NAME" | grep -q '/'; then
echo -e "${RED}❌ Missing slash separator${NC}"
echo "Format: <type>/<description>"
return 1
fi
DESC=$(echo "$BRANCH_NAME" | sed -E 's/^[a-z]+\/(.*)$/\1/')
# Check description exists
if [ -z "$DESC" ]; then
echo -e "${RED}❌ Missing description${NC}"
return 1
fi
# Check description is lowercase with hyphens
if ! echo "$DESC" | grep -qE '^[a-z0-9-]+$'; then
echo -e "${RED}❌ Description must be lowercase with hyphens only${NC}"
echo "Current: '$DESC'"
echo "Allowed: a-z, 0-9, hyphens"
return 1
fi
# Check no consecutive hyphens
if echo "$DESC" | grep -q '--'; then
echo -e "${RED}❌ No consecutive hyphens allowed${NC}"
return 1
fi
# Check doesn't start or end with hyphen
if echo "$DESC" | grep -qE '^-|-$'; then
echo -e "${RED}❌ Description cannot start or end with hyphen${NC}"
return 1
fi
# Check minimum length
if [ ${#DESC} -lt 3 ]; then
echo -e "${RED}❌ Description too short (${#DESC} < 3 chars)${NC}"
return 1
fi
# Check maximum length
if [ ${#DESC} -gt 50 ]; then
echo -e "${YELLOW}⚠️ Warning: Description is long (${#DESC} > 50 chars)${NC}"
echo "Consider using shorter branch names"
fi
return 0
}
# Main validation
echo "🔍 Validating branch name..."
echo ""
echo "Branch: $BRANCH_NAME"
echo ""
# Skip validation for protected branches
if is_protected_branch; then
echo -e "${GREEN}✅ Protected branch (validation skipped)${NC}"
exit 0
fi
# Track errors
ERRORS=0
# Run all validations
if ! validate_format; then
echo -e "${RED}❌ Invalid branch name format${NC}"
echo ""
echo "Expected format:"
echo " <type>/<description-with-hyphens>"
echo ""
echo "Examples:"
echo " feature/user-authentication"
echo " bugfix/login-timeout"
echo " hotfix/critical-security-issue"
echo " release/v1.2.0"
echo ""
ERRORS=$((ERRORS + 1))
else
if ! validate_type; then
ERRORS=$((ERRORS + 1))
fi
if ! validate_description; then
ERRORS=$((ERRORS + 1))
fi
fi
# Check for common mistakes
WARNINGS=0
# Warn about uppercase letters
if echo "$BRANCH_NAME" | grep -qE '[A-Z]'; then
echo -e "${YELLOW}⚠️ Warning: Branch name contains uppercase letters${NC}"
echo "Branch names should be lowercase"
WARNINGS=$((WARNINGS + 1))
fi
# Warn about underscores
if echo "$BRANCH_NAME" | grep -q '_'; then
echo -e "${YELLOW}⚠️ Warning: Branch name contains underscores${NC}"
echo "Use hyphens instead: ${BRANCH_NAME//_/-}"
WARNINGS=$((WARNINGS + 1))
fi
# Warn about spaces
if echo "$BRANCH_NAME" | grep -q ' '; then
echo -e "${YELLOW}⚠️ Warning: Branch name contains spaces${NC}"
echo "Use hyphens instead"
WARNINGS=$((WARNINGS + 1))
fi
# Suggest better names for common patterns
suggest_better_name() {
local SUGGESTED=""
# Convert to lowercase
SUGGESTED=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]')
# Replace underscores with hyphens
SUGGESTED=$(echo "$SUGGESTED" | tr '_' '-')
# Remove special characters
SUGGESTED=$(echo "$SUGGESTED" | sed 's/[^a-z0-9\/-]/-/g')
# Remove consecutive hyphens
SUGGESTED=$(echo "$SUGGESTED" | sed 's/--*/-/g')
# Remove leading/trailing hyphens
SUGGESTED=$(echo "$SUGGESTED" | sed 's/^-//' | sed 's/-$//')
if [ "$SUGGESTED" != "$BRANCH_NAME" ]; then
echo ""
echo -e "${YELLOW}💡 Suggested name: $SUGGESTED${NC}"
fi
}
# Result
echo ""
if [ $ERRORS -eq 0 ]; then
echo -e "${GREEN}✅ Branch name is valid${NC}"
if [ $WARNINGS -gt 0 ]; then
echo -e "${YELLOW} ($WARNINGS warning(s))${NC}"
suggest_better_name
fi
exit 0
else
echo -e "${RED}❌ Branch name validation failed${NC}"
echo -e "${RED} $ERRORS error(s)${NC}"
suggest_better_name
echo ""
echo "Rename the branch:"
echo " git branch -m $BRANCH_NAME <new-name>"
exit 1
fi
#!/bin/bash
# Automated Git Hooks Setup
# Installs Husky, lint-staged, and commitlint with recommended configuration
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🔧 Git Hooks Setup${NC}"
echo "=================="
echo ""
# Check if package.json exists
if [ ! -f "package.json" ]; then
echo -e "${RED}❌ package.json not found${NC}"
echo "This script must be run from the project root"
exit 1
fi
# Check if npm is installed
if ! command -v npm &> /dev/null; then
echo -e "${RED}❌ npm is not installed${NC}"
exit 1
fi
echo -e "${BLUE}📦 Installing dependencies...${NC}"
echo ""
# Install Husky
echo "Installing Husky..."
npm install --save-dev husky
# Install lint-staged
echo "Installing lint-staged..."
npm install --save-dev lint-staged
# Install commitlint
echo "Installing commitlint..."
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Install ESLint and Prettier (if not already installed)
if ! npm list eslint &> /dev/null; then
echo "Installing ESLint..."
npm install --save-dev eslint
fi
if ! npm list prettier &> /dev/null; then
echo "Installing Prettier..."
npm install --save-dev prettier
fi
echo -e "${GREEN}✅ Dependencies installed${NC}"
echo ""
# Initialize Husky
echo -e "${BLUE}🎣 Initializing Husky...${NC}"
npx husky init
# Create commitlint configuration
echo -e "${BLUE}📝 Creating commitlint configuration...${NC}"
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert'
]
],
'subject-case': [2, 'never', ['upper-case', 'pascal-case', 'start-case']],
'header-max-length': [2, 'always', 100],
'body-max-line-length': [2, 'always', 72],
'scope-case': [2, 'always', 'lower-case']
}
};
EOF
echo -e "${GREEN}✅ commitlint.config.js created${NC}"
echo ""
# Create lint-staged configuration
echo -e "${BLUE}📝 Creating lint-staged configuration...${NC}"
# Add lint-staged to package.json
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg['lint-staged'] = {
'*.{js,jsx,ts,tsx}': [
'eslint --fix',
'prettier --write'
],
'*.{json,md,yml,yaml}': [
'prettier --write'
]
};
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo -e "${GREEN}✅ lint-staged configuration added to package.json${NC}"
echo ""
# Create pre-commit hook
echo -e "${BLUE}🎣 Creating pre-commit hook...${NC}"
cat > .husky/pre-commit << 'EOF'
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run lint-staged
npx lint-staged
# Check for console.log in staged files
if git diff --cached | grep -E "^\+.*console\.log"; then
echo "⚠️ Warning: console.log found in staged files"
echo "Remove console.log or use --no-verify to skip this check"
exit 1
fi
EOF
chmod +x .husky/pre-commit
echo -e "${GREEN}✅ pre-commit hook created${NC}"
echo ""
# Create commit-msg hook
echo -e "${BLUE}🎣 Creating commit-msg hook...${NC}"
cat > .husky/commit-msg << 'EOF'
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Validate commit message format
npx --no -- commitlint --edit $1
EOF
chmod +x .husky/commit-msg
echo -e "${GREEN}✅ commit-msg hook created${NC}"
echo ""
# Create pre-push hook
echo -e "${BLUE}🎣 Creating pre-push hook...${NC}"
cat > .husky/pre-push << 'EOF'
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Get current branch
branch=$(git rev-parse --abbrev-ref HEAD)
# Prevent direct push to main
if [ "$branch" = "main" ]; then
echo "⛔ Cannot push directly to main branch"
echo "Please create a pull request instead"
exit 1
fi
# Run tests (if test script exists)
if grep -q '"test"' package.json; then
echo "🧪 Running tests..."
npm test
fi
EOF
chmod +x .husky/pre-push
echo -e "${GREEN}✅ pre-push hook created${NC}"
echo ""
# Update package.json scripts
echo -e "${BLUE}📝 Updating package.json scripts...${NC}"
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
// Add prepare script for Husky
if (!pkg.scripts) pkg.scripts = {};
pkg.scripts.prepare = 'husky install';
// Add lint and format scripts if they don't exist
if (!pkg.scripts.lint) {
pkg.scripts.lint = 'eslint . --ext .js,.jsx,.ts,.tsx';
}
if (!pkg.scripts['lint:fix']) {
pkg.scripts['lint:fix'] = 'eslint . --ext .js,.jsx,.ts,.tsx --fix';
}
if (!pkg.scripts.format) {
pkg.scripts.format = 'prettier --write .';
}
if (!pkg.scripts['format:check']) {
pkg.scripts['format:check'] = 'prettier --check .';
}
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo -e "${GREEN}✅ package.json scripts updated${NC}"
echo ""
# Create .prettierrc if it doesn't exist
if [ ! -f ".prettierrc" ]; then
echo -e "${BLUE}📝 Creating .prettierrc...${NC}"
cat > .prettierrc << 'EOF'
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false
}
EOF
echo -e "${GREEN}✅ .prettierrc created${NC}"
echo ""
fi
# Create .eslintrc.js if it doesn't exist
if [ ! -f ".eslintrc.js" ] && [ ! -f ".eslintrc.json" ]; then
echo -e "${BLUE}📝 Creating .eslintrc.js...${NC}"
cat > .eslintrc.js << 'EOF'
module.exports = {
extends: ['eslint:recommended'],
env: {
node: true,
es2021: true,
},
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'no-console': 'warn',
},
};
EOF
echo -e "${GREEN}✅ .eslintrc.js created${NC}"
echo ""
fi
# Summary
echo -e "${GREEN}✅ Git hooks setup complete!${NC}"
echo ""
echo "Installed hooks:"
echo " • pre-commit - Runs linting and formatting on staged files"
echo " • commit-msg - Validates commit message format"
echo " • pre-push - Prevents direct push to main, runs tests"
echo ""
echo "Configuration files created:"
echo " • commitlint.config.js"
echo " • .prettierrc"
echo " • .eslintrc.js"
echo ""
echo "Package.json updated with:"
echo " • lint-staged configuration"
echo " • npm scripts (lint, format, prepare)"
echo ""
echo "Usage:"
echo " npm run lint - Run ESLint"
echo " npm run lint:fix - Fix ESLint issues"
echo " npm run format - Format code with Prettier"
echo " npm test - Run tests (if configured)"
echo ""
echo "Commit format:"
echo " <type>[optional scope]: <description>"
echo ""
echo " Examples:"
echo " feat: add user authentication"
echo " fix(api): resolve timeout issue"
echo " docs: update README"
echo ""
echo "To skip hooks (emergency only):"
echo " git commit --no-verify"
echo " git push --no-verify"
echo ""
echo -e "${YELLOW}💡 Test the setup by making a commit!${NC}"
#!/bin/bash
# Validate Commit Message Format
# Enforces conventional commit format: <type>[optional scope]: <description>
set -e
# Get commit message (either from file or stdin)
if [ -n "$1" ]; then
COMMIT_MSG=$(cat "$1")
else
COMMIT_MSG=$(cat)
fi
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Valid commit types
VALID_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
# Commit message pattern
# Format: <type>[optional scope]: <description>
PATTERN="^(${VALID_TYPES})(\([a-z0-9-]+\))?!?: .{1,100}$"
# Extract first line (subject)
SUBJECT=$(echo "$COMMIT_MSG" | head -n 1)
# Validation functions
validate_format() {
if ! echo "$SUBJECT" | grep -qE "$PATTERN"; then
return 1
fi
return 0
}
validate_type() {
TYPE=$(echo "$SUBJECT" | sed -E 's/^([a-z]+).*/\1/')
if ! echo "$TYPE" | grep -qE "^(${VALID_TYPES})$"; then
echo -e "${RED}❌ Invalid type: '$TYPE'${NC}"
echo ""
echo "Valid types:"
echo " feat - New feature"
echo " fix - Bug fix"
echo " docs - Documentation only"
echo " style - Formatting, missing semicolons"
echo " refactor - Code restructuring"
echo " perf - Performance improvement"
echo " test - Adding tests"
echo " build - Build system changes"
echo " ci - CI configuration"
echo " chore - Maintenance tasks"
echo " revert - Revert previous commit"
return 1
fi
return 0
}
validate_scope() {
# Scope is optional, but if present must be lowercase
if echo "$SUBJECT" | grep -q '('; then
SCOPE=$(echo "$SUBJECT" | sed -E 's/^[a-z]+\(([^)]+)\).*/\1/')
if ! echo "$SCOPE" | grep -qE '^[a-z0-9-]+$'; then
echo -e "${RED}❌ Invalid scope: '$SCOPE'${NC}"
echo "Scope must be lowercase with hyphens only"
return 1
fi
fi
return 0
}
validate_description() {
# Extract description (after colon)
if ! echo "$SUBJECT" | grep -q ':'; then
echo -e "${RED}❌ Missing colon after type/scope${NC}"
echo "Format: <type>[scope]: <description>"
return 1
fi
DESC=$(echo "$SUBJECT" | sed -E 's/^[a-z]+(\([^)]+\))?!?: (.*)$/\2/')
# Check description exists
if [ -z "$DESC" ]; then
echo -e "${RED}❌ Missing description${NC}"
return 1
fi
# Check description is lowercase
if echo "$DESC" | grep -qE '^[A-Z]'; then
echo -e "${RED}❌ Description must start with lowercase${NC}"
echo "Current: '$DESC'"
echo "Correct: '$(echo "$DESC" | sed 's/^\(.\)/\L\1/')'"
return 1
fi
# Check description doesn't end with period
if echo "$DESC" | grep -q '\.$'; then
echo -e "${RED}❌ Description must not end with period${NC}"
return 1
fi
# Check length
if [ ${#DESC} -gt 100 ]; then
echo -e "${RED}❌ Description too long (${#DESC} > 100 chars)${NC}"
return 1
fi
if [ ${#DESC} -lt 3 ]; then
echo -e "${RED}❌ Description too short (${#DESC} < 3 chars)${NC}"
return 1
fi
return 0
}
validate_subject_length() {
if [ ${#SUBJECT} -gt 100 ]; then
echo -e "${RED}❌ Subject line too long (${#SUBJECT} > 100 chars)${NC}"
return 1
fi
return 0
}
# Main validation
echo "🔍 Validating commit message..."
echo ""
echo "Subject: $SUBJECT"
echo ""
# Track errors
ERRORS=0
# Run all validations
if ! validate_format; then
echo -e "${RED}❌ Invalid commit message format${NC}"
echo ""
echo "Expected format:"
echo " <type>[optional scope]: <description>"
echo ""
echo "Examples:"
echo " feat: add user authentication"
echo " fix(api): resolve timeout issue"
echo " feat(auth)!: redesign authentication API"
echo ""
ERRORS=$((ERRORS + 1))
else
if ! validate_type; then
ERRORS=$((ERRORS + 1))
fi
if ! validate_scope; then
ERRORS=$((ERRORS + 1))
fi
if ! validate_description; then
ERRORS=$((ERRORS + 1))
fi
if ! validate_subject_length; then
ERRORS=$((ERRORS + 1))
fi
fi
# Check for warnings
WARNINGS=0
# Warn about merge commits
if echo "$SUBJECT" | grep -qE "^Merge"; then
echo -e "${YELLOW}⚠️ Warning: Merge commit detected${NC}"
echo "Consider using squash and merge for cleaner history"
WARNINGS=$((WARNINGS + 1))
fi
# Warn about WIP commits
if echo "$SUBJECT" | grep -qiE "\bwip\b"; then
echo -e "${YELLOW}⚠️ Warning: WIP commit detected${NC}"
echo "Remember to squash WIP commits before merging"
WARNINGS=$((WARNINGS + 1))
fi
# Result
echo ""
if [ $ERRORS -eq 0 ]; then
echo -e "${GREEN}✅ Commit message is valid${NC}"
if [ $WARNINGS -gt 0 ]; then
echo -e "${YELLOW} ($WARNINGS warning(s))${NC}"
fi
exit 0
else
echo -e "${RED}❌ Commit message validation failed${NC}"
echo -e "${RED} $ERRORS error(s)${NC}"
echo ""
echo "Fix the commit message or use --no-verify to skip validation"
exit 1
fi
Related skills
FAQ
Which Git branching strategy should a small SaaS team use?
GitHub Flow suits web apps with continuous deployment and small-to-medium teams, keeping main always production-ready via PRs.
How do conventional commits enable automated versioning?
feat bumps MINOR, fix bumps PATCH, and a breaking change (feat! or BREAKING CHANGE footer) bumps MAJOR.