Documentation Index
Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
Use this file to discover all available pages before exploring further.
Git Hooks & Automation
Git hooks are scripts that run automatically every time a particular event occurs in a Git repository. They are the “event listeners” of the Git world — invisible quality gates that catch mistakes before they reach the codebase.What are Git Hooks?
Hooks are stored in the.git/hooks directory. They are executable scripts (bash, Python, Node, anything your system can run) that Git invokes at specific points in its workflow. If a hook exits with a non-zero status, the Git action is aborted — this is what makes hooks powerful as quality gates.
Think of hooks like the bouncer at a nightclub door: they check your commit before it gets in, and if something is wrong (failing tests, bad formatting, missing JIRA ticket), you are turned away until you fix it.
Common Hooks
| Hook | When it runs | Use Case |
|---|---|---|
| pre-commit | Before git commit executes | Linting, formatting, running fast unit tests. Catch issues before they enter history. |
| commit-msg | After you write the message | Enforcing commit message patterns (e.g., JIRA-123: ... or Conventional Commits format). |
| pre-push | Before git push sends data | Running integration tests, preventing accidental pushes to main/production branches. |
| prepare-commit-msg | Before editor opens | Auto-populating commit messages with branch name or ticket number. |
| post-merge | After git merge completes | Auto-running npm install when package.json changes after pulling. |
Creating a Hook (Manual)
Create a file.git/hooks/pre-commit:
Automating with Husky (JavaScript/Node)
Sharing hooks via.git/hooks is hard because that directory is not committed to version control. Husky solves this by storing hooks in a .husky/ directory (which IS committed) and configuring Git’s core.hooksPath to point there during npm install. Every developer who runs npm install gets the hooks automatically — no manual setup.
1. Install Husky
2. Add a Hook
This creates a.husky/pre-commit file that Git will execute before every commit.
git commit, npm test runs first. If tests fail, the commit is rejected. The developer fixes the issue locally instead of breaking the shared branch.
Lint-Staged
Running tests on the entire project for every commit is slow — on a large codebase, it can take minutes, which defeats the purpose of fast feedback. lint-staged solves this by running scripts only on the files that are currently staged for commit. If you changed 3 files out of 500, only those 3 get linted. Add alint-staged config to your package.json. Each key is a glob pattern matching staged files; the value is the command to run on those files:
Key Takeaways
- Use Hooks to shift quality checks “left” (to the developer’s machine). Catching a linting error in 2 seconds locally is infinitely better than finding it 10 minutes later in CI.
- Use Husky to share hooks across your team. Without it, hooks are “honor system” and nobody uses them.
- Use Lint-Staged to keep commits fast. Slow hooks lead to
--no-verifybecoming team culture. - Never rely only on hooks. Developers can bypass them with
git commit --no-verify, and hooks do not run in GitHub’s web editor or squash-merge UI. Always run the same checks in CI as a safety net. Hooks are a convenience; CI is the enforcement.
Interview Deep-Dive
Your team's pre-commit hook runs ESLint, Prettier, and the full unit test suite. Developers are bypassing it with --no-verify on every commit. Diagnose the problem and propose a solution.
Your team's pre-commit hook runs ESLint, Prettier, and the full unit test suite. Developers are bypassing it with --no-verify on every commit. Diagnose the problem and propose a solution.
Strong Answer:
- The problem is not the developers — it is the hook. If developers consistently bypass a quality gate, the gate is too expensive for the feedback loop it occupies. Pre-commit hooks should run in under 10 seconds. A full unit test suite that takes 45+ seconds at the pre-commit stage is a workflow killer.
- My solution: restructure what runs where. Pre-commit hooks should only run lint-staged (ESLint and Prettier on staged files only, not the entire project). This takes 2-3 seconds and catches formatting and obvious errors. Move the full unit test suite to a pre-push hook or, better yet, to CI. Pre-push hooks are the right place for heavier checks because pushes happen less frequently than commits.
- Implementation: install lint-staged and configure it in
package.jsonto run ESLint--fixand Prettier--writeonly on staged*.{js,ts}files. The pre-commit hook callsnpx lint-staged. This is the standard pattern used by most major open-source projects. - Additionally, I would keep the full test suite in CI as the enforcing gate. Hooks are a convenience that catches issues early; CI is the authoritative gate that blocks merges. This two-layer approach means fast local feedback (hooks) plus reliable enforcement (CI).
Explain how Husky solves the hook-sharing problem. What happens under the hood when a new developer clones the repo and runs npm install?
Explain how Husky solves the hook-sharing problem. What happens under the hood when a new developer clones the repo and runs npm install?
Strong Answer:
- The core problem: Git hooks live in
.git/hooks/, which is not committed to version control. If a team member clones the repo, they get no hooks. Hooks are effectively opt-in and individual, which means they are never used consistently. - Husky solves this by storing hook scripts in a committed
.husky/directory (which IS tracked by Git) and configuring Git to use that directory as the hooks path. When Husky is initialized (npx husky init), it setscore.hooksPath=.huskyin the local Git config via apreparescript inpackage.json. - Here is what happens when a new developer clones and runs
npm install: Thepreparelifecycle script inpackage.jsonruns automatically afternpm install. This script executeshusky(orhusky installin older versions), which setsgit config core.hooksPath .husky. From that point forward, everygit commit,git push, etc. looks in.husky/for hook scripts instead of.git/hooks/. - The key insight is that Husky uses a standard Git feature (
core.hooksPath) to redirect hook resolution. No symlinks, no copying files, no post-install hacks. If a developer does not runnpm install(e.g., they are not a Node.js developer touching docs), hooks are not configured — which is a reasonable failure mode. - For non-Node projects (Python, Go, etc.), there are analogous tools:
pre-commit(Python-based, supports any language) andlefthook(Go-based, very fast). The principle is the same: committed hook definitions + automatic installation on project setup.
git commit --no-verify (or HUSKY=0 git commit) for automated commits because the CI pipeline has its own quality checks. Alternatively, set the HUSKY environment variable to 0 in CI to disable hooks entirely. The broader principle is that hooks are developer tools — CI has its own enforcement layer and should not depend on developer hooks. Some teams add a CI environment variable check in the hook script itself: [ -n "$CI" ] && exit 0.Design a Git hooks strategy for a team of 20 developers working on a monorepo with frontend (React), backend (Go), and infrastructure (Terraform) code. What runs where?
Design a Git hooks strategy for a team of 20 developers working on a monorepo with frontend (React), backend (Go), and infrastructure (Terraform) code. What runs where?
Strong Answer:
- Pre-commit (under 10 seconds): Use lint-staged to run language-specific linters only on staged files. For React: ESLint + Prettier on
*.{ts,tsx}. For Go:gofmtandgo veton*.go. For Terraform:terraform fmtandterraform validateon*.tf. Each linter runs in parallel because lint-staged supports concurrent execution. The total time should be under 5 seconds because we are only processing changed files. - Commit-msg (under 1 second): Validate commit message format using commitlint. Enforce Conventional Commits (
feat:,fix:,chore:, etc.) and require a JIRA ticket reference (e.g.,PROJ-123). This costs almost nothing in time and pays enormous dividends in automated changelog generation and release management. - Pre-push (30-60 seconds): Run the affected test suites. For a monorepo, use a tool like Turborepo, Nx, or Bazel to determine which packages are affected by the changes and run only those tests. Do not run the full test suite (which could be 20+ minutes in a monorepo). If the affected-package detection is not available, run only the tests in the directories that were modified.
- CI (the enforcing gate): Full test suite across all affected packages, integration tests, security scanning (Snyk, Trivy), and deployment previews. CI is the authoritative gate — nothing merges without passing CI, regardless of whether hooks passed locally.
- What I explicitly would NOT do: run the full monorepo test suite in pre-commit (too slow), run Terraform
planin hooks (requires cloud credentials and takes too long), or enforce hooks in CI (CI has its own checks).
npx turbo run test --filter=...[HEAD] which runs tests for everything affected by the current changes. In CI, the same command runs with broader coverage. The key is that the dependency graph is explicit (defined in package.json or workspace.json), not inferred — so the tool knows that changing @company/utils requires testing @company/frontend and @company/api.Next: Linux Crash Course →