What's Actually Happening

Git hooks are scripts that run automatically before or after Git events like commit, push, or merge. When hooks don't run, usually the hook file lacks execute permission, is in wrong location, or has script errors.

The Symptom

bash
$ git commit -m "test"
# No hook output, commit happens immediately
# pre-commit hook should have run but didn't

You expected hook to: - Run tests - Check formatting - Validate commit message - Block bad commits

But nothing happened.

Why This Happens

  1. 1.Missing execute permission - Hook file not executable (most common)
  2. 2.Wrong filename - Hook must be named exactly (e.g., pre-commit, not pre-commit.sh)
  3. 3.Wrong location - Hooks must be in .git/hooks/
  4. 4.Script errors - Hook script has syntax errors or wrong shebang
  5. 5.Hooks disabled globally - Core.hooksPath configured incorrectly

Step 1: Check Hook Files Exist

bash
ls -la .git/hooks/

Shows hook templates and active hooks:

bash
total 16
drwxr-xr-x  2 user user 4096 Apr  3 10:00 .
drwxr-xr-x  8 user user 4096 Apr  3 10:00 ..
-rwxr-xr-x  1 user user  478 Apr  3 10:00 pre-commit
-rwxr-xr-x  1 user user  478 Apr  3 10:00 pre-commit.sample

Files without .sample extension are active hooks.

Step 2: Check Execute Permission

bash
ls -l .git/hooks/pre-commit

Must show -rwxr-xr-x (execute permission for all).

If shows -rw-r--r-- (no execute):

bash
chmod +x .git/hooks/pre-commit
chmod +x .git/hooks/post-commit
chmod +x .git/hooks/pre-push

Or add execute to all hooks:

bash
chmod +x .git/hooks/*

Step 3: Verify Hook Filename

Hook names must be exact:

HookFilename (exact)
Pre-commitpre-commit
Post-commitpost-commit
Pre-pushpre-push
Commit-msgcommit-msg
Pre-rebasepre-rebase

Wrong: pre-commit.sh, pre-commit.bash, pre-commit.py Correct: pre-commit (no extension)

If named wrong:

bash
mv .git/hooks/pre-commit.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

Step 4: Check Script Content

bash
cat .git/hooks/pre-commit

Must start with shebang:

bash
#!/bin/sh
# or
#!/bin/bash
# or
#!/usr/bin/env python

If missing shebang, script won't run correctly.

Also check for script errors:

```bash # Test hook manually ./.git/hooks/pre-commit

# Or with bash debug bash -x .git/hooks/pre-commit ```

Step 5: Check Global Hooks Configuration

bash
git config --get core.hooksPath

If this returns a path, Git uses that path instead of .git/hooks/.

To use default hooks location:

bash
git config --unset core.hooksPath

Or set custom hooks path:

bash
git config core.hooksPath .githooks
chmod +x .githooks/*

Step 6: Test Hook Manually

Run hook directly to debug:

```bash # Test pre-commit hook ./.git/hooks/pre-commit

# Check exit code echo $? # 0 = success, non-0 = failure (blocks commit) ```

If hook runs manually but not during Git operations, check configuration.

Step 7: Use Hook Management Tools

For shared hooks across team, use tools:

Husky (popular for npm projects):

bash
npm install husky --save-dev
npx husky install
npx husky add .husky/pre-commit "npm test"

pre-commit (Python tool):

bash
pip install pre-commit
# Create .pre-commit-config.yaml
pre-commit install

These tools handle permissions and setup automatically.

Step 8: Debug Hook Execution

For detailed debugging:

```bash # Run Git command with debug GIT_TRACE=1 git commit -m "test"

# See hook execution git commit -m "test" 2>&1 | grep hook ```

Step 9: Check for Core Hooks Disabled

bash
git config --get core.hooksPath
git config --get init.templateDir

If hooks path is empty string or invalid, hooks won't run.

Verify the Fix

After fixing:

```bash # Test hook runs git commit --allow-empty -m "test"

# Should see hook output (if hook prints anything) # Commit should be blocked if hook exits non-zero

# Check hook execution trace GIT_TRACE=1 git commit -m "test" 2>&1 ```

Prevention Tips

When setting up hooks:

```bash # Always add execute permission chmod +x .git/hooks/pre-commit

# Use proper shebang #!/bin/sh set -e # Exit on error

# Test hook immediately after creating ./.git/hooks/pre-commit

# Use hook managers for team projects npm install husky ```