Stop Pushing Broken Code: Clean Git Hooks Without External Packages
How many times have you pushed a commit only to realize 3 minutes later that you left a console.log , a formatting issue, or a broken unit test in your pull request? Most JavaScript and TypeScript teams immediately reach for external tools like Husky or lint-staged. While those tools are great, many developers don't realize that Git has had native client-side hooks built-in since day one —and you…
Many developers push code with bugs such as console logs, formatting errors, or broken unit tests, which they discover only after pushing, wasting time. JavaScript and TypeScript teams often rely on external tools like Husky or lint-staged for protection, but these require npm dependencies. Git has had built-in client-side hooks since day one, and developers need not use any external packages to safeguard their repositories.
To set up a native, version-controlled pre-commit hook in under two minutes, first understand the issue with the default .git/hooks folder. Git stores hooks in this directory, but it never commits this folder to remote repositories, so teammates won't get your hooks, and you won't get theirs. Git 2.9 introduced a configuration setting, core.hooksPath, that solves this issue.
Step 1: Tell Git where to look for hooks by creating a tracked directory in your project root called .githooks. After creating this directory, instruct Git to read hooks from this location using the command: git config core.hooksPath .githooks. In a team project, add this line to the npm prepare script in package.json so it automatically runs upon npm install.
Step 2: Create your native pre-commit hook inside the newly created .githooks/ folder. Name the file pre-commit (no extension) and make it executable: touch .githooks/pre-commit, then chmod +x .githooks/pre-commit. Inside the pre-commit script, add your validation logic. For example, run your linter or type-checker, block unwanted console.log leftovers, and exit with appropriate status codes.
Step 3: Test your new pre-commit hook. Whenever you run git commit, Git will execute the .githooks/pre-commit script before creating the commit snapshot. If the script exits with a zero status, the commit will proceed. If any test or lint fails (resulting in non-zero exit), Git will immediately abort the commit, keeping your Git log clean and free of broken code.
Using native Git hooks offers several advantages: zero dependencies, no extra build-step overhead, instant execution speed, and compatibility with any stack. Small features like core.hooksPath save developers hours of CI debugging and help maintain clean codebases. Share your experience with native Git hooks or preferred package managers like Husky in the comments below.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.