[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-44f9da68-e7b1-4c59-a215-2f1b393e0158":3,"$fP1VXb0TrANd4qfW1wr8d_qYdQ4T_jk9BltNtNlH-8AU":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"44f9da68-e7b1-4c59-a215-2f1b393e0158","git-hooks-automation","熟练掌握使用 Husky、lint-staged、pre-commit 框架和 commitlint 设置 Git 钩子。在代码达到 CI 之前自动化代码质量关卡、格式化、代码检查和提交信息强制执行。","cat_coding_review","mod_coding","sickn33,coding","---\nname: git-hooks-automation\ndescription: \"Master Git hooks setup with Husky, lint-staged, pre-commit framework, and commitlint. Automate code quality gates, formatting, linting, and commit message enforcement before code reaches CI.\"\nrisk: safe\nsource: community\ndate_added: \"2026-03-07\"\n---\n\n# Git Hooks Automation\n\nAutomate code quality enforcement at the Git level. Set up hooks that lint, format, test, and validate before commits and pushes ever reach your CI pipeline — catching issues in seconds instead of minutes.\n\n## When to Use This Skill\n\n- User asks to \"set up git hooks\" or \"add pre-commit hooks\"\n- Configuring Husky, lint-staged, or the pre-commit framework\n- Enforcing commit message conventions (Conventional Commits, commitlint)\n- Automating linting, formatting, or type-checking before commits\n- Setting up pre-push hooks for test runners\n- Migrating from Husky v4 to v9+ or adopting hooks from scratch\n- User mentions \"pre-commit\", \"commit-msg\", \"pre-push\", \"lint-staged\", or \"githooks\"\n\n## Git Hooks Fundamentals\n\nGit hooks are scripts that run automatically at specific points in the Git workflow. They live in `.git\u002Fhooks\u002F` and are not version-controlled by default — which is why tools like Husky exist.\n\n### Hook Types & When They Fire\n\n| Hook | Fires When | Common Use |\n|---|---|---|\n| `pre-commit` | Before commit is created | Lint, format, type-check staged files |\n| `prepare-commit-msg` | After default msg, before editor | Auto-populate commit templates |\n| `commit-msg` | After user writes commit message | Enforce commit message format |\n| `post-commit` | After commit is created | Notifications, logging |\n| `pre-push` | Before push to remote | Run tests, check branch policies |\n| `pre-rebase` | Before rebase starts | Prevent rebase on protected branches |\n| `post-merge` | After merge completes | Install deps, run migrations |\n| `post-checkout` | After checkout\u002Fswitch | Install deps, rebuild assets |\n\n### Native Git Hooks (No Framework)\n\n```bash\n# Create a pre-commit hook manually\ncat > .git\u002Fhooks\u002Fpre-commit \u003C\u003C 'EOF'\n#!\u002Fbin\u002Fsh\nset -e\n\n# Run linter on staged files only\nSTAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.(js|ts|jsx|tsx)$' || true)\n\nif [ -n \"$STAGED_FILES\" ]; then\n  echo \"🔍 Linting staged files...\"\n  echo \"$STAGED_FILES\" | xargs npx eslint --fix\n  echo \"$STAGED_FILES\" | xargs git add  # Re-stage after fixes\nfi\nEOF\nchmod +x .git\u002Fhooks\u002Fpre-commit\n```\n\n**Problem**: `.git\u002Fhooks\u002F` is local-only and not shared with the team. Use a framework instead.\n\n## Husky + lint-staged (Node.js Projects)\n\nThe modern standard for JavaScript\u002FTypeScript projects. Husky manages Git hooks; lint-staged runs commands only on staged files for speed.\n\n### Quick Setup (Husky v9+)\n\n```bash\n# Install\nnpm install --save-dev husky lint-staged\n\n# Initialize Husky (creates .husky\u002F directory)\nnpx husky init\n\n# The init command creates a pre-commit hook — edit it:\necho \"npx lint-staged\" > .husky\u002Fpre-commit\n```\n\n### Configure lint-staged in `package.json`\n\n```json\n{\n  \"lint-staged\": {\n    \"*.{js,jsx,ts,tsx}\": [\n      \"eslint --fix --max-warnings=0\",\n      \"prettier --write\"\n    ],\n    \"*.{css,scss}\": [\n      \"prettier --write\",\n      \"stylelint --fix\"\n    ],\n    \"*.{json,md,yml,yaml}\": [\n      \"prettier --write\"\n    ]\n  }\n}\n```\n\n### Add Commit Message Linting\n\n```bash\n# Install commitlint\nnpm install --save-dev @commitlint\u002Fcli @commitlint\u002Fconfig-conventional\n\n# Create commitlint config\ncat > commitlint.config.js \u003C\u003C 'EOF'\nmodule.exports = {\n  extends: ['@commitlint\u002Fconfig-conventional'],\n  rules: {\n    'type-enum': [2, 'always', [\n      'feat', 'fix', 'docs', 'style', 'refactor',\n      'perf', 'test', 'build', 'ci', 'chore', 'revert'\n    ]],\n    'subject-max-length': [2, 'always', 72],\n    'body-max-line-length': [2, 'always', 100]\n  }\n};\nEOF\n\n# Add commit-msg hook\necho \"npx --no -- commitlint --edit \\$1\" > .husky\u002Fcommit-msg\n```\n\n### Add Pre-Push Hook\n\n```bash\n# Run tests before pushing\necho \"npm test\" > .husky\u002Fpre-push\n```\n\n### Complete Husky Directory Structure\n\n```\nproject\u002F\n├── .husky\u002F\n│   ├── pre-commit        # npx lint-staged\n│   ├── commit-msg        # npx --no -- commitlint --edit $1\n│   └── pre-push          # npm test\n├── commitlint.config.js\n├── package.json          # lint-staged config here\n└── ...\n```\n\n## pre-commit Framework (Python \u002F Polyglot)\n\nLanguage-agnostic framework that works with any project. Hooks are defined in YAML and run in isolated environments.\n\n### Setup\n\n```bash\n# Install (Python required)\npip install pre-commit\n\n# Create config\ncat > .pre-commit-config.yaml \u003C\u003C 'EOF'\nrepos:\n  # Built-in checks\n  - repo: https:\u002F\u002Fgithub.com\u002Fpre-commit\u002Fpre-commit-hooks\n    rev: v4.6.0\n    hooks:\n      - id: trailing-whitespace\n      - id: end-of-file-fixer\n      - id: check-yaml\n      - id: check-json\n      - id: check-added-large-files\n        args: ['--maxkb=500']\n      - id: check-merge-conflict\n      - id: detect-private-key\n\n  # Python formatting\n  - repo: https:\u002F\u002Fgithub.com\u002Fpsf\u002Fblack\n    rev: 24.4.2\n    hooks:\n      - id: black\n\n  # Python linting\n  - repo: https:\u002F\u002Fgithub.com\u002Fastral-sh\u002Fruff-pre-commit\n    rev: v0.4.4\n    hooks:\n      - id: ruff\n        args: ['--fix']\n      - id: ruff-format\n\n  # Shell script linting\n  - repo: https:\u002F\u002Fgithub.com\u002Fshellcheck-py\u002Fshellcheck-py\n    rev: v0.10.0.1\n    hooks:\n      - id: shellcheck\n\n  # Commit message format\n  - repo: https:\u002F\u002Fgithub.com\u002Fcompilerla\u002Fconventional-pre-commit\n    rev: v3.2.0\n    hooks:\n      - id: conventional-pre-commit\n        stages: [commit-msg]\nEOF\n\n# Install hooks into .git\u002Fhooks\u002F\npre-commit install\npre-commit install --hook-type commit-msg\n\n# Run against all files (first time)\npre-commit run --all-files\n```\n\n### Key Commands\n\n```bash\npre-commit install              # Install hooks\npre-commit run --all-files      # Run on everything (CI or first setup)\npre-commit autoupdate           # Update hook versions\npre-commit run \u003Chook-id>        # Run a specific hook\npre-commit clean                # Clear cached environments\n```\n\n## Custom Hook Scripts (Any Language)\n\nFor projects not using Node or Python, write hooks directly in shell.\n\n### Portable Pre-Commit Hook\n\n```bash\n#!\u002Fbin\u002Fsh\n# .githooks\u002Fpre-commit — Team-shared hooks directory\nset -e\n\necho \"=== Pre-Commit Checks ===\"\n\n# 1. Prevent commits to main\u002Fmaster\nBRANCH=$(git symbolic-ref --short HEAD 2>\u002Fdev\u002Fnull || echo \"detached\")\nif [ \"$BRANCH\" = \"main\" ] || [ \"$BRANCH\" = \"master\" ]; then\n  echo \"❌ Direct commits to $BRANCH are not allowed. Use a feature branch.\"\n  exit 1\nfi\n\n# 2. Check for debugging artifacts\nif git diff --cached --diff-filter=ACM | grep -nE '(console\\.log|debugger|binding\\.pry|import pdb)' > \u002Fdev\u002Fnull 2>&1; then\n  echo \"⚠️  Debug statements found in staged files:\"\n  git diff --cached --diff-filter=ACM | grep -nE '(console\\.log|debugger|binding\\.pry|import pdb)'\n  echo \"Remove them or use git commit --no-verify to bypass.\"\n  exit 1\nfi\n\n# 3. Check for large files (>1MB)\nLARGE_FILES=$(git diff --cached --name-only --diff-filter=ACM | while read f; do\n  size=$(wc -c \u003C \"$f\" 2>\u002Fdev\u002Fnull || echo 0)\n  if [ \"$size\" -gt 1048576 ]; then echo \"$f ($((size\u002F1024))KB)\"; fi\ndone)\nif [ -n \"$LARGE_FILES\" ]; then\n  echo \"❌ Large files detected:\"\n  echo \"$LARGE_FILES\"\n  exit 1\nfi\n\n# 4. Check for secrets patterns\nif git diff --cached --diff-filter=ACM | grep -nEi '(AKIA[0-9A-Z]{16}|sk-[a-zA-Z0-9]{48}|ghp_[a-zA-Z0-9]{36}|password\\s*=\\s*[\"\\x27][^\"\\x27]+[\"\\x27])' > \u002Fdev\u002Fnull 2>&1; then\n  echo \"🚨 Potential secrets detected in staged changes! Review before committing.\"\n  exit 1\nfi\n\necho \"✅ All pre-commit checks passed\"\n```\n\n### Share Custom Hooks via `core.hooksPath`\n\n```bash\n# In your repo, set a shared hooks directory\ngit config core.hooksPath .githooks\n\n# Add to project setup docs or Makefile\n# Makefile\nsetup:\n\tgit config core.hooksPath .githooks\n\tchmod +x .githooks\u002F*\n```\n\n## CI Integration\n\nHooks are a first line of defense, but CI is the source of truth.\n\n### Run pre-commit in CI (GitHub Actions)\n\n```yaml\n# .github\u002Fworkflows\u002Flint.yml\nname: Lint\non: [push, pull_request]\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-python@v5\n        with:\n          python-version: '3.12'\n      - uses: pre-commit\u002Faction@v3.0.1\n```\n\n### Run lint-staged in CI (Validation Only)\n\n```yaml\n# Validate that lint-staged would pass (catch bypassed hooks)\nname: Lint Check\non: [pull_request]\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 20\n      - run: npm ci\n      - run: npx eslint . --max-warnings=0\n      - run: npx prettier --check .\n```\n\n## Common Pitfalls & Fixes\n\n### Hooks Not Running\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| Hooks silently skipped | Not installed in `.git\u002Fhooks\u002F` | Run `npx husky init` or `pre-commit install` |\n| \"Permission denied\" | Hook file not executable | `chmod +x .husky\u002Fpre-commit` |\n| Hooks run but wrong ones | Stale hooks from old setup | Delete `.git\u002Fhooks\u002F` contents, reinstall |\n| Works locally, fails in CI | Different Node\u002FPython versions | Pin versions in CI config |\n\n### Performance Issues\n\n```json\n\u002F\u002F ❌ Slow: runs on ALL files every commit\n{\n  \"scripts\": {\n    \"precommit\": \"eslint src\u002F && prettier --write src\u002F\"\n  }\n}\n\n\u002F\u002F ✅ Fast: lint-staged runs ONLY on staged files\n{\n  \"lint-staged\": {\n    \"*.{js,ts}\": [\"eslint --fix\", \"prettier --write\"]\n  }\n}\n```\n\n### Bypassing Hooks (When Needed)\n\n```bash\n# Skip all hooks for a single commit\ngit commit --no-verify -m \"wip: quick save\"\n\n# Skip pre-push only\ngit push --no-verify\n\n# Skip specific pre-commit hooks\nSKIP=eslint git commit -m \"fix: update config\"\n```\n\n> **Warning**: Bypassing hooks should be rare. If your team frequently bypasses, the hooks are too slow or too strict — fix them.\n\n## Migration Guide\n\n### Husky v4 → v9 Migration\n\n```bash\n# 1. Remove old Husky\nnpm uninstall husky\nrm -rf .husky\n\n# 2. Remove old config from package.json\n# Delete \"husky\": { \"hooks\": { ... } } section\n\n# 3. Install fresh\nnpm install --save-dev husky\nnpx husky init\n\n# 4. Recreate hooks\necho \"npx lint-staged\" > .husky\u002Fpre-commit\necho \"npx --no -- commitlint --edit \\$1\" > .husky\u002Fcommit-msg\n\n# 5. Clean up — old Husky used package.json config,\n#    new Husky uses .husky\u002F directory with plain scripts\n```\n\n### Adopting Hooks on an Existing Project\n\n```bash\n# Step 1: Start with formatting only (low friction)\n# lint-staged config:\n{ \"*.{js,ts}\": [\"prettier --write\"] }\n\n# Step 2: Add linting after team adjusts (1-2 weeks later)\n{ \"*.{js,ts}\": [\"eslint --fix\", \"prettier --write\"] }\n\n# Step 3: Add commit message linting\n# Step 4: Add pre-push test runner\n\n# Gradual adoption prevents team resistance\n```\n\n## Key Principles\n\n- **Staged files only** — Never lint the entire codebase on every commit\n- **Auto-fix when possible** — `--fix` flags reduce developer friction\n- **Fast hooks** — Pre-commit should complete in \u003C 5 seconds\n- **Fail loud** — Clear error messages with actionable fixes\n- **Team-shared** — Use Husky or `core.hooksPath` so hooks are version-controlled\n- **CI as backup** — Hooks are convenience; CI is the enforcer\n- **Gradual adoption** — Start with formatting, add linting, then testing\n\n## Related Skills\n\n- `@codebase-audit-pre-push` - Deep audit before GitHub push\n- `@verification-before-completion` - Verification before claiming work is done\n- `@bash-pro` - Advanced shell scripting for custom hooks\n- `@github-actions-templates` - CI\u002FCD workflow templates\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,132,1952,"2026-05-16 13:20:03",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"代码审查","review","mdi-magnify-scan","代码质量分析、安全审查",4,145,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"38c80586-faa9-43a4-85d8-fbe4427f6f05","1.0.0","git-hooks-automation.zip",4875,"uploads\u002Fskills\u002F44f9da68-e7b1-4c59-a215-2f1b393e0158\u002Fgit-hooks-automation.zip","08f9e43881d4e135a92f021e56ec4eb648baf7bad64f492ea03882d1caec922f","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":11942}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]