Git & CI/CD Advanced

Resolving Git pre-commit Hook Execution Failures on CentOS Stream / Rocky Linux

Troubleshoot and fix Git pre-commit hook bash execution errors on CentOS Stream or Rocky Linux, often caused by permissions, environment, or SELinux issues.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Troubleshoot and fix Git pre-commit hook bash execution errors on CentOS Stream or Rocky Linux, often caused by permissions, environment, or SELinux issues.

When working with Git on CentOS Stream or Rocky Linux systems, encountering a pre-commit hook execution failure can halt your development workflow. These client-side hooks are powerful tools for enforcing code quality, style, or other checks before a commit is finalized. However, misconfigurations, permission issues, or environment discrepancies can lead to the dreaded "failed execution" error, particularly with Bash scripts. This guide provides a highly technical, step-by-step approach to diagnose and resolve these common issues.

Symptom & Error Signature

You attempt to commit your changes using git commit, but instead of a successful commit, you receive an error message in your terminal similar to the following:

$ git commit -m "Fix: Implement feature X"

pre-commit hook failed (exit code 1)

# Or, with more verbose output from the hook itself:
$ git commit -m "Refactor: Cleanup old code"

/path/to/your/repo/.git/hooks/pre-commit: line 5: some_command: command not found
error: failed to execute pre-commit hook (exit code 127) # exit code might vary

The key indicators are the "pre-commit hook failed" message, often accompanied by a specific exit code (e.g., 1, 127, 2), and potentially error output from the script itself if it attempted to run.

Root Cause Analysis

Multiple factors can cause a pre-commit Bash hook to fail execution on CentOS Stream or Rocky Linux:

  1. Incorrect Permissions: The hook script (.git/hooks/pre-commit) lacks execute permissions, preventing the system from running it.
  2. Missing or Incorrect Shebang: The script doesn't start with #!/bin/bash (or the correct interpreter path), or the specified interpreter isn't available.
  3. Environment PATH Discrepancies: Git hooks execute in a stripped-down environment. Commands or tools used within your hook script (e.g., php-cs-fixer, eslint, node, custom scripts) might not be found because their directories are not in the PATH environment variable available to the hook. This is a very common issue.
  4. Syntax Errors in Script: Basic Bash syntax errors within the pre-commit script itself can cause it to fail prematurely.
  5. Missing Dependencies: The hook script relies on external tools or packages that are not installed on the system (e.g., jq, xmlstarlet, specific language linters).
  6. SELinux Restrictions: On RHEL-based systems like CentOS Stream and Rocky Linux, SELinux can prevent scripts from executing or accessing resources, even if file permissions are correct. This is often an overlooked culprit.
  7. Shell Differences: While sh often symlinks to bash on these systems, there can be subtle differences in how bash behaves when invoked as sh or in non-interactive modes, leading to unexpected script failures.

Step-by-Step Resolution

Follow these steps to systematically diagnose and resolve your Git pre-commit hook execution issues.

1. Verify Hook Executability and Shebang

Ensure your hook script has the necessary execute permissions and a correct shebang.

# Navigate to your Git repository root
cd /path/to/your/git/repo

# Check permissions
ls -l .git/hooks/pre-commit
# Expected output: -rwxrwxr-x ... (the 'x' indicates execute permission)

# If 'x' is missing, add execute permissions
chmod +x .git/hooks/pre-commit

# Inspect the shebang line
head -n 1 .git/hooks/pre-commit
# Expected output: #!/bin/bash (or #!/usr/bin/env bash if you prefer)

The shebang line #!/bin/bash (or #!/usr/bin/env bash) must be the very first line of your script. Ensure there are no preceding blank lines or invisible characters.

2. Debug the Hook Script

Add debugging lines to your pre-commit script to pinpoint failures.

Open .git/hooks/pre-commit with your editor and add the following lines near the top, right after the shebang:

#!/bin/bash
set -euxo pipefail # -e: exit on error, -u: treat unset vars as error, -x: print commands and their args, -o pipefail: catch errors in pipelines

# Redirect stderr and stdout to a log file for easier debugging
exec 2> /tmp/pre-commit-hook.log
exec 1>&2

echo "Starting pre-commit hook at $(date)"
echo "Current PATH: $PATH"
echo "Current PWD: $(pwd)"
echo "Current User: $(whoami)"
echo "-----------------------------------"

# ... rest of your hook script ...

Now, try git commit again. All output (including command executions and errors) will be redirected to /tmp/pre-commit-hook.log. Examine this file for clues.

3. Address Environment PATH Issues

A common cause of "command not found" errors is that the PATH environment variable within the hook's execution context is not the same as your interactive shell.

If your debugging log shows command not found for tools you know are installed, explicitly set the PATH within your hook script or use absolute paths.

#!/bin/bash
set -euxo pipefail
exec 2> /tmp/pre-commit-hook.log
exec 1>&2

# Explicitly set PATH to include common binary directories
# Adjust this to include paths relevant to your tools (e.g., ~/.nvm/versions/node/vX.Y.Z/bin for Node.js)
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"

echo "Updated PATH: $PATH"
echo "-----------------------------------"

# Example: now 'php-cs-fixer' or 'npm' should be found if they are in these paths
# php-cs-fixer fix .
# npm test

Always try to use absolute paths for critical commands within hooks, e.g., /usr/bin/php instead of php, especially if there's any ambiguity. If using language-specific tools installed via package managers (like npm or composer), ensure their global installation paths are included in the PATH or invoke them with their full path.

4. Check for Missing Dependencies

If the hook complains about a specific command not being found, it might be that the tool itself isn't installed.

# Example: If 'php-cs-fixer' is missing, install it (if globally via Composer)
composer global require friendsofphp/php-cs-fixer

# Example: If 'jq' (JSON processor) is missing
sudo dnf install jq

# Example: If 'node' or 'npm' is missing (consider nvm or official nodejs repo)
sudo dnf module install nodejs:18 # For NodeJS 18 (adjust version as needed)

5. Analyze Script Syntax

Even expert scripters make mistakes. Use a linter to check your Bash script's syntax.

# Install ShellCheck (if not already installed)
sudo dnf install ShellCheck

# Run ShellCheck on your hook script
shellcheck .git/hooks/pre-commit

ShellCheck will provide warnings and errors with suggestions for correction.

6. SELinux Troubleshooting

SELinux is a common source of "permission denied" or "operation not permitted" errors that aren't immediately obvious from file permissions alone.

Temporarily disabling SELinux with setenforce 0 should only be done for troubleshooting purposes in a controlled environment. Never leave SELinux disabled in production. Re-enable it with setenforce 1 immediately after testing.

  1. Temporarily Disable SELinux (for testing):
    sudo setenforce 0
    
  2. Attempt git commit again. If it now works, SELinux was the culprit.
  3. Re-enable SELinux:
    sudo setenforce 1
    
  4. Analyze SELinux Audit Logs:
    sudo ausearch -m AVC -ts recent -i
    
    Look for denied entries related to git or your hook script's path.
  5. Generate a Custom SELinux Policy: If you find AVC denials, you can create a custom policy.
    # Capture relevant denials
    sudo audit2allow -a -M git_hooks
    # This will create git_hooks.te (Type Enforcement) and git_hooks.pp (Policy Package)
    
    # Install the policy
    sudo semodule -i git_hooks.pp
    
    This will allow the specific actions that SELinux was previously denying.

7. Test Hook Manually

Run the pre-commit script directly from your terminal, navigating into the repository first. This helps isolate issues from the git command itself.

cd /path/to/your/git/repo
bash .git/hooks/pre-commit
# Or, if you need the full path to the script
/bin/bash .git/hooks/pre-commit

This will execute the script in your current shell's environment, which can help determine if the problem is specific to the hook's execution environment or the script logic itself.

8. Use a Wrapper Script (Advanced)

For complex environments where hooks need a very specific setup (e.g., sourcing a .nvm or .pyenv script, loading specific environment variables from ~/.bashrc or ~/.profile), you might create a small wrapper script.

#!/bin/bash

# Source your profile or environment setup
# Be cautious: .bashrc is for interactive shells.
# For non-interactive, consider a dedicated env file or setup script.
# Example: source /etc/profile # or /home/youruser/.bash_profile

# Or, explicitly set up specific tools
# 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

# Now execute your actual hook logic or another script
# For example, if your actual logic is in `scripts/run_checks.sh`:
/bin/bash scripts/run_checks.sh "$@"

Then, your .git/hooks/pre-commit would simply call this wrapper:

#!/bin/bash
/path/to/your/repo/scripts/git_pre_commit_wrapper.sh "$@"

By following these detailed steps, you should be able to identify and resolve the "Git commit hooks pre-commit failed execution" error on your CentOS Stream or Rocky Linux system, restoring your Git workflow to optimal efficiency.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

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.