Migrating from Legacy Git Hooks to Husky v9
Migrating from legacy git hooks to Husky v9 requires a structured approach to prevent workflow disruption. Legacy .git/hooks/ implementations frequently suffer from cross-platform path resolution failures and inconsistent permission states. This guide maps existing shell logic to modern Husky v9 lifecycle equivalents while enforcing strict validation gates.
Symptom Identification & Legacy Hook Audit
Legacy hook failures typically manifest as silent bypasses, cross-platform execution errors, or missing executable permissions. Auditing the current state prevents unintended regression during migration. Run find .git/hooks -type f -executable -print to enumerate active scripts.
Verify shebang consistency across all files. Prioritize #!/usr/bin/env bash over hardcoded paths like #!/bin/sh. Document exit codes and stdout/stderr behavior before removal to establish a baseline for validation.
When auditing legacy script execution contexts, align your repository standards with established Git Automation & CI/CD Hook Engineering practices to ensure consistent lifecycle management.
Environment Preparation & Husky v9 Initialization
Removing legacy hooks requires careful isolation to preserve repository integrity. WARNING: Deleting .git/hooks/ contents permanently removes local validation gates. Commit or back up critical scripts before proceeding. Execute rm -rf .git/hooks/* while preserving any README.md or tracking files.
Initialize the modern hook directory structure by running npx husky init. This command generates the husky/ directory and configures baseline lifecycle files. Configure the package manager lifecycle by running npm pkg set scripts.prepare="husky".
This ensures the prepare script executes automatically during npm ci or yarn install. Follow the directory structure standards and CLI initialization patterns documented in Local Hook Configuration with Husky to prevent path resolution conflicts.
Script Migration & Lifecycle Mapping
Translating legacy shell logic into Husky v9 requires explicit lifecycle mapping. Husky v9 deprecates husky install and relies entirely on the prepare script and the husky/ directory. Move pre-commit, commit-msg, and pre-push logic into the new directory.
Create executable files with explicit #!/usr/bin/env sh shebangs to guarantee POSIX compliance across environments. Replace inline CLI invocations with package manager script references. Use npm run lint or pnpm run format instead of raw CLI calls to leverage workspace configurations.
Apply executable permissions immediately after file creation. Run chmod +x husky/* post-creation to prevent permission drift during cross-platform clones. This guarantees consistent execution on Git v2.30+ installations.
Validation, Edge Cases & CI/CD Alignment
Verification must cover execution consistency across macOS, Linux, and Windows Subsystem for Linux. Test the migration by staging a change and triggering a commit: git add . && git commit -m "chore: validate husky v9 migration". Monitor stdout for expected linting or formatting output.
Use time git commit to profile execution latency and detect performance regressions. Handle CI/CD alignment by validating environment variable behavior. Set HUSKY=0 or CI=true to bypass local hooks during automated pipeline runs. This prevents redundant validation and reduces build times.
Ensure lint-staged integration relies on package.json configuration rather than legacy .lintstagedrc files. Cross-platform path resolution is handled automatically via $(dirname -- "$0")/_/husky.sh in generated scripts. Validate Node.js >= 18.0.0 compatibility to guarantee modern runtime support.