Git Hygiene Enforcer
Enforce consistent, high-quality git practices across your team.
Core Workflow Choose conventions: Select commit format (Conventional Commits, Angular, etc.) Setup commit hooks: Install commitlint with git hooks Configure branch rules: Define naming patterns and protection Create PR templates: Standardize pull request descriptions Add workflows: GitHub Actions or GitLab CI for automated checks Document process: Write CONTRIBUTING.md with git guidelines Provide bypasses: Document emergency override procedures Conventional Commits
Format:
Types:
feat: New feature fix: Bug fix docs: Documentation changes style: Code style changes (formatting, etc.) refactor: Code refactoring test: Test additions or changes chore: Build/tool changes perf: Performance improvements ci: CI/CD changes
Examples:
feat(auth): add OAuth2 login fix(api): resolve race condition in user endpoint docs(readme): update installation instructions refactor(utils): simplify date formatting logic
Commit Hook Setup Using Husky + Commitlint Install dependencies: npm install --save-dev @commitlint/cli @commitlint/config-conventional husky npx husky init
Configure commitlint (commitlint.config.js): module.exports = { extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", [ "feat", "fix", "docs", "style", "refactor", "test", "chore", "perf", "ci", ], ], "subject-case": [2, "never", ["upper-case"]], "subject-empty": [2, "never"], "subject-full-stop": [2, "never", "."], "header-max-length": [2, "always", 100], }, };
Add commit-msg hook (.husky/commit-msg):
!/bin/sh
npx --no -- commitlint --edit $1
Using pre-commit (Python)
.pre-commit-config.yaml
repos: - repo: https://github.com/compilerla/conventional-pre-commit rev: v3.0.0 hooks: - id: conventional-pre-commit stages: [commit-msg]
Branch Naming Conventions
Pattern:
Examples:
feature/AUTH-123-oauth-login bugfix/API-456-user-race-condition hotfix/PROD-789-payment-error refactor/DB-321-optimize-queries
Branch Protection Rules:
Require PR reviews (1-2 reviewers) Require status checks to pass Require branches to be up to date Enforce linear history (no merge commits) Require signed commits (optional) Pull Request Templates .github/pull_request_template.md
Description
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
Related Issue
Closes #
How Has This Been Tested?
- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual testing
Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own 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)
Alternative: Simple Template
What
Why
How
Testing
GitHub Actions Workflow .github/workflows/pr-checks.yml name: PR Checks
on: pull_request: branches: [main, develop]
jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0
- name: Validate PR title
uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check branch naming
run: |
BRANCH="${{ github.head_ref }}"
if [[ ! $BRANCH =~ ^(feature|bugfix|hotfix|refactor|docs|chore)/.+ ]]; then
echo "Branch name doesn't follow convention: <type>/<description>"
exit 1
fi
- name: Lint commits
uses: wagoid/commitlint-github-action@v5
- name: Check for merge commits
run: |
if git log --merges origin/${{ github.base_ref }}..HEAD | grep -q 'Merge'; then
echo "Merge commits detected. Please rebase your branch."
exit 1
fi
Git Configuration .gitattributes
Auto detect text files and perform LF normalization
- text=auto
Explicitly mark files as text
.js text .ts text .json text .md text *.yml text
Binary files
.png binary .jpg binary .gif binary .ico binary .woff binary .woff2 binary
.gitignore Best Practices
Dependencies
node_modules/ vendor/
Environment
.env .env.local
Build outputs
dist/ build/ *.log
IDE
.vscode/ .idea/ *.swp
OS
.DS_Store Thumbs.db
Code Review Guidelines CONTRIBUTING.md Section
Pull Request Process
- Create a branch following naming convention:
type/description - Make commits using conventional commit format
- Write tests for new features or bug fixes
- Update documentation if APIs change
- Ensure CI passes before requesting review
- Request review from 1-2 team members
- Address feedback and update PR
- Squash and merge when approved
Code Review Checklist
Reviewers should verify:
- [ ] Code is clear and understandable
- [ ] Tests cover new/changed code
- [ ] No obvious bugs or security issues
- [ ] Follows project conventions
- [ ] Documentation is updated
- [ ] No unnecessary changes included
Constructive feedback:
- Be specific and actionable
- Assume good intent
- Ask questions instead of making demands
- Praise good solutions
Commit Message Validation commit-msg Hook Example
!/bin/bash
.husky/commit-msg
commit_msg=$(cat "$1")
Check conventional commit format
if ! echo "$commit_msg" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|ci)((.+))?: .+'; then
echo "Error: Commit message doesn't follow Conventional Commits format"
echo "Format:
Check message length
if [ ${#commit_msg} -gt 100 ]; then echo "Error: Commit message too long (max 100 characters)" exit 1 fi
Emergency Bypass Instructions Skipping Hooks (Use Sparingly)
Skip commit message validation
git commit --no-verify -m "hotfix: critical production fix"
Force push (use with caution)
git push --force-with-lease
Override PR checks (requires admin)
Use GitHub UI: "Merge without waiting for checks"
When Bypass is Acceptable Production hotfixes: Critical bugs affecting users Reverts: Rolling back problematic changes Emergency: Infrastructure outages Bypass Documentation
Document in CONTRIBUTING.md:
Emergency Procedures
In rare cases, you may need to bypass git hooks:
-
Commit without hooks:
git commit --no-verify -
Only for production hotfixes
-
Fix commit message in follow-up PR
-
Force push:
git push --force-with-lease - After approved history rewrite
- Coordinate with team first
Always create a follow-up PR to fix any bypassed checks.
Recommended Workflow
Development Workflow
- Start work
bash git checkout main git pull git checkout -b feature/TICKET-123-new-feature
Make changes
Make your changes
git add . git commit -m "feat(api): add user search endpoint"
Keep updated
git fetch origin git rebase origin/main
Push and create PR
git push origin feature/TICKET-123-new-feature
Create PR via GitHub/GitLab
Address feedback
Make changes
git add . git commit -m "fix: address review feedback" git push
Merge
Squash and merge via UI Delete branch after merge
Installation Checklist
- [ ] Commitlint config (commitlint.config.js)
- [ ] Git hooks (.husky/ or .git/hooks/)
- [ ] PR template (.github/pull_request_template.md)
- [ ] Branch protection rules (via GitHub settings)
- [ ] CI workflow for PR validation
- [ ] CONTRIBUTING.md with git guidelines
- [ ] .gitattributes for consistent line endings
- [ ] Emergency bypass documentation
Best Practices
- Keep commits atomic: One logical change per commit
- Write descriptive messages: Explain why, not just what
- Reference tickets: Include issue/ticket IDs
- Rebase before merging: Keep history clean
- Review your own PR first: Self-review catches many issues
- Respond to feedback promptly: Don't leave PRs hanging
- Delete merged branches: Keep repository tidy
- Use draft PRs: For work-in-progress changes