skills/git-best-practices/SKILL.md
Expert in Git workflows, conventions, and patterns for modern development teams and AI agents. Activate on: branching strategy, commit conventions, git hooks, pre-commit, husky, lint-staged, trunk-based development, git worktree, monorepo git, PR review workflow, conventional commits, git workflow. NOT for: CI/CD pipelines (use github-actions-pipeline-builder), repository hosting (use devops-automator), multi-agent orchestration (use multi-agent-coordination).
npx skillsauth add curiositech/windags-skills git-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in the specific Git workflows, conventions, and patterns that make development teams — and solo developers working with AI coding agents — productive. Not "how to use git" but "how to use git well."
Activate on: "branching strategy", "commit conventions", "git hooks", "pre-commit", "husky", "lint-staged", "trunk-based development", "git worktree", "monorepo git", "PR review workflow", "conventional commits", "git workflow", "merge strategy", "rebase vs merge", "git conflict resolution"
NOT for: CI/CD pipelines -> github-actions-pipeline-builder | Repo hosting -> devops-automator | Multi-agent orchestration -> multi-agent-coordination
| Strategy | Team Size | Release Cadence | Complexity | Best For | |----------|-----------|-----------------|------------|----------| | Trunk-Based | Any | Continuous | Low | SaaS, microservices, AI agents | | GitHub Flow | 2-20 | Daily/weekly | Low | Most teams, open source | | GitFlow | 10+ | Scheduled releases | High | Mobile apps, versioned libraries | | Ship/Show/Ask | Any | Continuous | Medium | High-trust teams |
main ──●──●──●──●──●──●──●──●──●── (always deployable)
\ / \ / \ /
●─● ●──● ●──●──●
(hours) (1 day) (2 days max)
Rules:
main is always deployable. Period.main triggers CI. Green means deployable.When NOT to use trunk-based:
main ──●──────●──────●──────●──── (protected, PR-only merges)
\ / \ / \ /
●──● ●──● ●──●
feature fix feature
Rules:
main is protected. No direct pushes.main, do work, open PR.main.| Category | Action | When | |----------|--------|------| | Ship | Merge directly to main | Typos, config, deps, obvious fixes | | Show | Open PR, merge immediately, review async | Straightforward changes, established patterns | | Ask | Open PR, wait for review | New architecture, risky changes, unfamiliar code |
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
| Type | When | Bumps |
|------|------|-------|
| feat | New user-facing feature | MINOR |
| fix | Bug fix | PATCH |
| docs | Documentation only | - |
| style | Formatting, whitespace (not CSS) | - |
| refactor | Code change that neither fixes nor adds | - |
| perf | Performance improvement | - |
| test | Adding/fixing tests | - |
| build | Build system, dependencies | - |
| ci | CI/CD changes | - |
| chore | Maintenance, tooling | - |
| revert | Reverts a previous commit | - |
feat(auth)!: replace API key with OAuth2
BREAKING CHANGE: The `apiKey` parameter in `createClient()` has been
removed. Use `oauth: { clientId, clientSecret }` instead.
Migration: npx @your-tool/codemod v2-to-v3
The ! after the type/scope and BREAKING CHANGE: footer both signal a MAJOR version bump.
# BAD - what, not why
fix: update code
feat: add stuff
chore: changes
# GOOD - why, with context
fix(auth): prevent token refresh race condition on slow networks
feat(search): add fuzzy matching for skill names with Levenshtein distance
chore(deps): bump vitest to 3.1 for Node 22 compatibility
# Install
npm install -D @commitlint/cli @commitlint/config-conventional
# Configure
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
# Hook into Husky
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
# Install
npm install -D husky lint-staged
# Initialize husky
npx husky init
# The init command creates .husky/ and adds a prepare script
# Edit .husky/pre-commit:
echo "npx lint-staged" > .husky/pre-commit
// package.json
{
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,yml}": [
"prettier --write"
],
"*.test.{ts,tsx}": [
"vitest related --run"
]
}
}
Install Husky at root, scope lint-staged by package path: "packages/core/**/*.ts": "pnpm --filter @your-org/core lint". Each package gets its own lint command, preventing cross-package leak.
| Hook | Max Time | What to Run |
|------|----------|-------------|
| pre-commit | <5 seconds | Lint + format staged files only |
| commit-msg | <1 second | commitlint validation |
| pre-push | <30 seconds | Type check + fast test suite |
If hooks are slow, developers skip them with --no-verify. Keep them fast.
# .husky/pre-commit — fast, staged files only
npx lint-staged
# .husky/commit-msg — validate message format
npx --no -- commitlint --edit $1
# .husky/pre-push — more thorough checks
pnpm typecheck && pnpm test --run
Worktrees let you check out multiple branches simultaneously in separate directories, sharing the same .git history. This is the primary isolation primitive for parallel AI agents.
# Create a worktree for a feature
git worktree add ../myproject-feature-auth feature/auth
# List active worktrees
git worktree list
# Work in the worktree (it's a normal directory)
cd ../myproject-feature-auth
# ... make changes, commit, push ...
# Remove when done
git worktree remove ../myproject-feature-auth
# Agent 1: Working on auth
git worktree add ../project-agent-auth -b agent/auth-refactor
# Agent 2: Working on API (parallel, isolated)
git worktree add ../project-agent-api -b agent/api-endpoints
# Agent 3: Working on tests (parallel, isolated)
git worktree add ../project-agent-tests -b agent/test-coverage
# Each agent has full filesystem isolation
# Commits in any worktree are visible to all (shared .git)
# When agents finish, merge results
git merge agent/auth-refactor
git merge agent/api-endpoints
git merge agent/test-coverage
# Clean up
git worktree remove ../project-agent-auth
git worktree remove ../project-agent-api
git worktree remove ../project-agent-tests
| Problem | Solution |
|---------|----------|
| Port conflicts | Each worktree needs unique dev server ports (use env vars or port-daddy) |
| Shared node_modules | Run npm install in each worktree (separate node_modules per worktree) |
| Database conflicts | Use per-worktree database names or Docker containers |
| Same branch twice | Git prevents this — you cannot check out a branch that's checked out elsewhere |
| IDE confusion | Open each worktree as a separate workspace/window |
| Stale worktrees | Run git worktree prune periodically to clean up |
../project-<purpose>-<branch-slug>
# Examples:
../windags-agent-auth-refactor
../windags-agent-api-endpoints
../windags-review-pr-142
../windags-experiment-new-executor
| Size | Lines Changed | Review Time | Recommendation | |------|---------------|-------------|----------------| | XS | 1-10 | Minutes | Ship or Show | | S | 10-100 | 15 min | Standard review | | M | 100-400 | 30 min | Standard review | | L | 400-1000 | 1 hour | Break it up if possible | | XL | 1000+ | Hours | Almost always should be split |
Every PR template should include: What (1-2 sentences, what and why) -> How (technical approach) -> Testing (steps + checkboxes) -> Screenshots (before/after for UI) -> Breaking Changes (none or migration path). Save as .github/pull_request_template.md.
Understand what/why, tests cover happy + edge path, no TODO without issue link, error handling present, no secrets in diff, breaking changes documented.
| Strategy | When | Command |
|----------|------|---------|
| Squash merge (default) | Feature branches, messy commits | git merge --squash feature/auth then single conventional commit |
| Rebase + FF merge | Linear history, each commit meaningful | git rebase main then git merge feature/auth |
| Merge commit | Long-running integration branches (rare) | git merge feature/auth |
Decision: Are all commits on the branch meaningful and tested? Yes -> rebase. No -> squash.
# Clone with sparse checkout
git clone --sparse --filter=blob:none https://github.com/org/monorepo.git
cd monorepo
# Check out only what you need
git sparse-checkout set packages/core packages/shared
# Log for one package
git log --oneline -- packages/core/
# Diff for one package
git diff main -- packages/ui/
# Blame within scope
git log --all --oneline -- packages/cli/src/index.ts
# .github/CODEOWNERS
packages/core/ @org/core-team
packages/ui/ @org/frontend-team
packages/cli/ @org/dx-team
docs/ @org/docs-team
.github/ @org/platform-team
Key settings every team should configure:
[pull] rebase = true # Rebase on pull instead of merge
[push] autoSetupRemote = true # Auto set upstream on first push
[merge] conflictstyle = zdiff3 # Better conflict markers with common ancestor
[diff] algorithm = histogram # Better diff output
[rerere] enabled = true # Remember conflict resolutions
[fetch] prune = true # Auto-delete stale remote branches
.gitignore essentials: node_modules/, .env*, dist/, .turbo/, .DS_Store, coverage/. Always commit lock files (pnpm-lock.yaml). Use gitignore.io for stack-specific templates. Set up ~/.gitignore_global for per-developer ignores.
Symptom: Branch diverges from main for weeks. Merge becomes a nightmare. Fix: Trunk-based development. Feature flags for incomplete work. Branch lives max 2 days.
Symptom: git log shows "wip", "stuff", "fix", "asdf".
Fix: Squash merge into a single conventional commit. Or use git rebase -i to clean up before PR.
Symptom: Developers routinely bypass pre-commit hooks. Fix: Hooks are too slow. Make them faster (lint-staged, not full project). Or move slow checks to pre-push.
Symptom: git push --force to main or shared feature branches.
Fix: Protect main in GitHub/GitLab settings. Use --force-with-lease if you must force push to your own branch.
Symptom: dist/, node_modules/, *.lock diffs pollute PRs.
Fix: Add to .gitignore. Only commit lock files (package-lock.json, pnpm-lock.yaml) — those belong in version control.
Symptom: API keys, passwords committed and "removed" in a later commit. They're still in history.
Fix: Use git-filter-repo to rewrite history. Rotate the exposed credentials immediately. Add .env to .gitignore before first commit.
Symptom: Anyone can push directly to main. No required reviews. No CI gate.
Fix: Enable branch protection: require PR, require 1+ review, require CI green, require up-to-date branch.
Symptom: Rebasing a branch that others have pulled causes history divergence. Fix: Only rebase your own local branches. Once pushed and shared, merge only.
[ ] Branching strategy documented and agreed upon by team
[ ] Conventional commit format enforced via commitlint + husky
[ ] Pre-commit hooks run lint + format on staged files only (< 5 seconds)
[ ] Pre-push hooks run typecheck + tests
[ ] Branch protection enabled on main (PR required, CI green, review required)
[ ] .gitignore covers dependencies, build output, env files, OS files
[ ] PR template exists with what/how/testing/breaking sections
[ ] Merge strategy chosen and configured (squash recommended)
[ ] CODEOWNERS file maps directories to responsible teams
[ ] git config includes rebase-on-pull, prune-on-fetch, zdiff3 conflicts
[ ] Worktree conventions documented for AI agent workflows
[ ] No secrets in git history (scanned with trufflehog or gitleaks)
[ ] Lock files (pnpm-lock.yaml) committed, generated output is not
.gitconfig recommendations, branch protection rules.github/pull_request_template.mddata-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.