Resolving Git pre-commit Hook Failed Execution Errors on Ubuntu 20.04 LTS
Troubleshoot Git pre-commit hook failures on Ubuntu 20.04 LTS, often due to permissions, shebang, or script errors. Restore your commit workflow.
Troubleshoot Git pre-commit hook failures on Ubuntu 20.04 LTS, often due to permissions, shebang, or script errors. Restore your commit workflow.
A failing Git pre-commit hook can halt your development workflow, preventing commits from being made and potentially disrupting CI/CD pipelines. This guide provides a highly technical, step-by-step approach to diagnose and resolve pre-commit hook execution errors specifically on Ubuntu 20.04 LTS, focusing on common bash-related issues. You'll learn to identify the root cause, from permission problems and incorrect shebangs to script logic errors and environment PATH discrepancies.
Symptom & Error Signature
When attempting to git commit, the process aborts, and you observe error messages in your terminal indicating that the pre-commit hook failed. The exact output can vary depending on the specific cause and whether you are using a hook manager like Husky.
Here are typical error signatures you might encounter:
Generic Bash Execution Failure
$ git commit -m "feat: Add new feature"
fatal: cannot run .git/hooks/pre-commit: No such file or directory
error: git-sh-setup: failed to find script directory in PATH
Permission Denied / Not Executable
$ git commit -m "fix: Resolve bug"
hint: The 'pre-commit' hook was ignored because it's not set as executable.
hint: You can change the permissions of the file by
hint: chmod +x .git/hooks/pre-commit
fatal: cannot run .git/hooks/pre-commit: Permission denied
Syntax Error within the Hook Script
$ git commit -m "refactor: Improve performance"
/home/user/my-project/.git/hooks/pre-commit: line 5: unexpected token `then'
/home/user/my-project/.git/hooks/pre-commit: line 5: `if [ "$1" == "--no-verify" ]; then'
External Tool Not Found (PATH Issue or Missing Dependency)
$ git commit -m "docs: Update README"
/home/user/my-project/.git/hooks/pre-commit: line 10: prettier --write: command not found
husky > pre-commit hook failed (exit 1)
Husky Specific Error (if used)
$ git commit -m "chore: Setup lint-staged"
husky > pre-commit (node v14.x)
env: node: No such file or directory
husky > pre-commit hook failed (exit 1)
Root Cause Analysis
The pre-commit hook is a simple executable script located at .git/hooks/pre-commit within your repository. Its failure to execute successfully can stem from several underlying issues:
- Incorrect File Permissions: The most common cause. The hook script must have executable permissions (
+x) for the Git client to run it. - Missing or Incorrect Shebang: The first line of a shell script, the "shebang" (e.g.,
#!/bin/bash), tells the operating system which interpreter to use. If it's missing, points to a non-existent interpreter, or has incorrect syntax, the script won't run. - Bash Script Syntax Errors: Errors within the script itself (e.g., typos, unclosed quotes, incorrect conditional statements) will cause the interpreter to fail.
- Environment PATH Discrepancies: The
PATHvariable inside a Git hook's execution environment might differ from your interactive shell, leading to "command not found" errors for tools likenode,npm,prettier,eslint, etc., that the hook relies on. - Missing External Dependencies: The hook script might call external programs (e.g.,
jq,prettier,lint-staged) that are not installed on the system or are not globally available in the hook'sPATH. - Incorrect Line Endings: If the script was created or edited on a Windows system, it might have
CRLFline endings. On Linux, scripts typically expectLFline endings, andCRLFcan cause parsing issues with the shebang or other commands. - Symlink Issues: If the
pre-commitfile is a symbolic link to another script (common with global hooks or framework setups), the target of the symlink might be broken or incorrect. - Husky/Hook Manager Configuration: If using a tool like Husky, its configuration (
.husky/pre-commitorpackage.jsonscripts) might be misconfigured, or the underlying Node.js environment might be missing or inaccessible.
Step-by-Step Resolution
Follow these steps to diagnose and resolve your pre-commit hook execution errors. We will assume the problematic hook is located at .git/hooks/pre-commit. Adjust paths if you're using a hook manager like Husky (e.g., .husky/pre-commit).
1. Verify Executable Permissions
The hook script must be executable. This is the most frequent cause of failure.
Check current permissions:
ls -l .git/hooks/pre-commitLook for an
xin the permission string (e.g.,-rwxr-xr-x). Ifxis missing (e.g.,-rw-r--r--), it's not executable.Make the script executable:
chmod +x .git/hooks/pre-commitRetry your commit:
git commit -m "Test after permissions fix"If it now works, you're done! Otherwise, proceed to the next step.
2. Inspect the Shebang Line
The shebang #!/bin/bash tells the system to use bash to execute the script.
Open the hook script:
nano .git/hooks/pre-commit # Or your preferred editor, e.g., vim .git/hooks/pre-commitVerify the first line: It should start with
#!. Common valid shebangs for bash scripts include:#!/bin/bashOr, for better portability across different Linux distributions where
bashmight not be directly in/bin:#!/usr/bin/env bashEnsure there are no spaces or characters before the
#!. Also, verify that the specified interpreter (e.g.,/bin/bashorbashforenv) actually exists on your system viawhich bash.
3. Debug Script Logic and Syntax
If permissions and shebang are correct, the problem lies within the script's logic or syntax.
Enable Debugging Output: Add
set -euxo pipefailright after the shebang line in yourpre-commitscript.set -e: Exit immediately if a command exits with a non-zero status.set -u: Treat unset variables as an error.set -x: Print commands and their arguments as they are executed (very verbose, but useful).set -o pipefail: The return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if all commands exit successfully.
#!/bin/bash set -euxo pipefail # Add this line # Your existing hook script logic follows...Manually Run the Hook for Detailed Output: Navigate to your repository's root and execute the hook directly. This will show you exactly what the script is trying to do and where it might be failing, especially with
set -xenabled.cd /path/to/your/repository ./.git/hooks/pre-commitIf the hook requires staged files to test its logic, you'll need to stage some changes before running it manually.
If the error points to a specific line number (e.g.,
line 5: unexpected token), focus your debugging efforts around that line in the script.
4. Investigate PATH and Environment Variables
Tools like npm, node, prettier, eslint, etc., might not be found because the PATH within the hook's execution environment is limited.
Echo PATH inside the hook: Temporarily add
echo "PATH: $PATH"to yourpre-commitscript to see whatPATHGit provides.#!/bin/bash echo "DEBUG: PATH=$PATH" # ... rest of your scriptCommit and observe the output. If essential directories are missing (e.g.,
/usr/local/binfor Node.js), that's your problem.Explicitly source environment variables (if necessary): If your project relies on
nvmor other environment managers, you might need to source their setup scripts within the hook.#!/bin/bash # For NVM users, ensure node/npm is available export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" # This loads nvm bash_completion # Your existing hook script logic follows... # Now commands like 'node' or 'npm' should be in PATHUse absolute paths for critical commands: As a workaround or for enhanced robustness, you can replace
prettierwith/usr/local/bin/prettier(or its absolute path determined bywhich prettier).# Instead of: # prettier --write . # Use: $(which prettier) --write .This ensures the exact binary is called.
5. Install Missing External Dependencies
If your hook uses a tool (e.g., jq, xmlstarlet, hadolint, markdownlint) that is not installed, it will fail with a "command not found" error.
Identify the missing command: The error message (e.g.,
prettier: command not found) usually indicates this.Install the dependency:
# Example for jq: sudo apt update sudo apt install jq # Example for a Node.js-based tool (like Prettier, ESLint, Lint-Staged) # Ensure Node.js and npm are installed first, then install globally or locally npm install -g prettier # Global install # or npm install --save-dev prettier # Project-local install (then ensure hook references local binary, e.g., ./node_modules/.bin/prettier)
6. Correct Line Endings
Windows line endings (CRLF) can cause issues on Linux systems.
Convert line endings:
sudo apt install dos2unix # Install if not already present dos2unix .git/hooks/pre-commitVerify conversion: Open the file in a text editor like
nanoorvimand check for^Mcharacters if they were present.
7. Check Symlink Integrity
If your pre-commit is a symlink, ensure its target is valid.
Check if it's a symlink:
ls -l .git/hooks/pre-commit # Output like: lrwxrwxrwx ... .git/hooks/pre-commit -> ../../hooks/pre-commit.shResolve the symlink target:
readlink -f .git/hooks/pre-commitThis command will output the absolute path to the actual script file. Verify this path is correct and the target file exists and is executable. If the symlink is broken, recreate it.
# Example: Recreate a symlink rm .git/hooks/pre-commit ln -s ../../hooks/pre-commit.sh .git/hooks/pre-commit chmod +x .git/hooks/pre-commit # Ensure target and symlink are executable
8. Temporarily Bypass the Hook (Use with Caution)
Bypassing commit hooks can lead to unlinted, untested, or incorrectly formatted code entering your repository. Only use this as a temporary measure for urgent commits or during deep debugging.
If you absolutely need to make a commit and cannot immediately fix the hook, you can bypass it:
git commit -m "Emergency commit (hook bypassed)" --no-verify
# Or the shorter form:
git commit -m "Emergency commit (hook bypassed)" -n
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.