This error occurs when Git tries to execute a commit-msg hook that doesn't exist or has an invalid configuration. The hook file may be missing, have incorrect permissions, contain an invalid shebang line, or reference a non-existent interpreter. The fix involves verifying the hook file exists and is properly configured.
The "cannot run .git/hooks/commit-msg: No such file or directory" error indicates that Git is attempting to execute a commit-msg hook script that either doesn't exist or cannot be found by the system. This error blocks your commit because Git is configured to run this hook but cannot locate the executable. Git hooks are scripts that run automatically at certain points in your Git workflow. The `commit-msg` hook specifically runs after you write a commit message but before the commit is finalized. It's commonly used for: - Validating commit message format (conventional commits) - Adding ticket numbers or prefixes automatically - Enforcing commit message standards across a team The error typically occurs when: - **Hook management tools like Husky were uninstalled** but left configuration behind - **The hook file references a missing interpreter** (wrong shebang line) - **The hook was manually deleted** but Git configuration still references it - **File encoding issues** prevent proper parsing of the hook script - **The hook file lacks execute permissions** (though this usually produces a different error) This is a configuration problem, not a Git bug. Your repository's hooks configuration expects a script that the system cannot locate or execute.
First, verify whether the commit-msg hook file actually exists:
Check the standard hooks directory:
# List all hooks
ls -la .git/hooks/
# Check specifically for commit-msg
ls -la .git/hooks/commit-msgCheck if Husky is configured:
# Look for Husky directory
ls -la .husky/
# Check for commit-msg in Husky
ls -la .husky/commit-msgCheck Git's hooks path configuration:
git config core.hooksPathIf this returns a path (like .husky), Git is looking for hooks in that directory instead of .git/hooks.
Based on what you found, choose the appropriate fix:
Option A: If Husky was uninstalled but config remains
# Remove the custom hooks path
git config --unset core.hooksPath
# Or remove it globally if set globally
git config --global --unset core.hooksPathOption B: If the hook file exists but is broken
# Remove the broken hook
rm .git/hooks/commit-msg
# Or if using Husky
rm .husky/commit-msgOption C: If you want to keep using hooks, reinstall Husky
# Install and initialize Husky
npm install husky --save-dev
npx husky init
# Or with yarn
yarn add husky --dev
npx husky initIf the hook file exists but has formatting issues:
Check the shebang line:
# View the first line of the hook
head -n 1 .git/hooks/commit-msgThe first line MUST be a valid shebang with no leading whitespace:
#!/bin/shor
#!/bin/bashFix encoding issues (Windows):
# Check for BOM (will show characters before #!/bin/sh)
file .git/hooks/commit-msg
# Convert to Unix line endings
dos2unix .git/hooks/commit-msg
# Or use sed
sed -i 's/\r$//' .git/hooks/commit-msgFix permissions:
chmod +x .git/hooks/commit-msgCreate a minimal working hook if needed:
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/sh
exit 0
EOF
chmod +x .git/hooks/commit-msgIf you need to make a commit immediately while troubleshooting:
Skip all hooks for one commit:
git commit --no-verify -m "Your commit message"The --no-verify flag (or -n for short) tells Git to skip pre-commit and commit-msg hooks.
Caution: This bypasses any validation the hook was performing. Use sparingly and fix the underlying issue rather than making this a habit.
Alternative - temporarily disable hooks globally:
# Disable hooks
git config core.hooksPath /dev/null
# Make your commit
git commit -m "Your commit message"
# Re-enable hooks
git config --unset core.hooksPathIf the issue stems from a removed Husky installation, clean up your package.json:
Check for leftover Husky configuration:
{
"scripts": {
"prepare": "husky install" // Remove this if Husky is uninstalled
}
}Remove from package.json if Husky is no longer used:
# Remove the prepare script
npm pkg delete scripts.prepare
# Or manually edit package.jsonIf you're keeping Husky, ensure it's properly installed:
# Fresh Husky setup (v9+)
npm install husky --save-dev
npx husky init
# This creates .husky/pre-commit
# Add commit-msg hook if needed:
echo "npx --no -- commitlint --edit $1" > .husky/commit-msgIf this error affects your whole team after cloning:
For projects using Husky:
Make sure Husky is in devDependencies and the prepare script is set:
{
"devDependencies": {
"husky": "^9.0.0"
},
"scripts": {
"prepare": "husky"
}
}After cloning, team members should run:
npm install
# This triggers the prepare script and sets up hooksFor projects using pre-commit (Python):
pip install pre-commit
pre-commit installDocument hook setup in your README so new team members know how to set up their environment.
Understanding Git Hooks Architecture:
Git hooks live in .git/hooks/ by default, but this can be changed with core.hooksPath. When you install Husky, it typically sets:
git config core.hooksPath .huskyThis redirects Git to look in .husky/ instead of .git/hooks/ for all hooks.
Why "No such file or directory" When the File Exists:
This error is misleading. It often means:
1. The shebang interpreter doesn't exist (#!/usr/bin/python3 but Python 3 isn't installed)
2. The file has CRLF line endings making the shebang invalid (#!/bin/sh\r is not a valid path)
3. The file has a UTF-8 BOM making the shebang unparseable
To diagnose:
# Check what the system thinks the file type is
file .git/hooks/commit-msg
# Should say: "POSIX shell script" or similar
# If it says "ASCII text" with no script type, shebang is broken
# Check for hidden characters
cat -A .git/hooks/commit-msg | head -1
# Should show: #!/bin/sh$
# Bad: ^M at end (CRLF) or weird characters at start (BOM)Hook Inheritance in Monorepos:
In monorepos, hooks are tricky because .git is at the root but you may run Git from subdirectories. Husky handles this, but if you remove Husky, the core.hooksPath setting might still point to a non-existent directory relative to where you're running Git.
Debugging Hook Execution:
# See exactly what Git is trying to execute
GIT_TRACE=1 git commit -m "test"This shows the full path Git attempts to use for hooks.
Platform-Specific Issues:
Windows:
- Ensure Git Bash is available if hooks use #!/bin/bash
- File permissions work differently; Git tracks the executable bit
- Use .cmd or .exe extensions for Windows-native scripts
- WSL and Windows Git can conflict if you mix them
macOS:
- /bin/bash is Bash 3.x (old); for newer features use /usr/local/bin/bash or /opt/homebrew/bin/bash
- Homebrew-installed interpreters have different paths than system ones
Linux:
- Most flexible; standard paths usually work
- Some distros don't have /bin/bash (use #!/usr/bin/env bash for portability)
The `#!/usr/bin/env` Trick:
For maximum portability, use:
#!/usr/bin/env bashInstead of:
#!/bin/bashThe env approach finds the interpreter in your PATH, which works across different systems where interpreters might be installed in different locations.
Security Considerations:
Git hooks can execute arbitrary code. Be cautious when:
- Cloning repositories from untrusted sources (hooks in .husky are in the repo)
- The .git/hooks directory is not in the repo, so traditional hooks don't spread
- Husky hooks ARE in the repo, which is convenient but requires trust
Review hook contents before running npm install on untrusted repositories.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server