A simple yet effective pre-commit hook for C and C++ projects that automatically formats and cleans up your code before each commit.
This pre-commit hook performs three main tasks on staged files:
- Remove trailing whitespaces - Cleans up trailing spaces and tabs at the end of lines
- Convert tabs to spaces - Replaces all tabs with 4 spaces for consistent indentation
- Format C/C++ code - Runs
clang-formaton all C/C++ source files
- General files (whitespace/tab cleanup):
.sh,.s,.S,.asm,.ld,.txt,.cmake,.clang-format - C/C++ source files (formatting):
.h,.c,.hpp,.cpp,.cppm
- clang-format must be installed and available in your PATH
- A
.clang-formatconfiguration file must be present in your git repository root - Bash shell - The hook is written in bash and uses bash-specific features
- ✅ Linux with bash
- ✅ macOS with bash or zsh (the script runs in bash via the
#!/bin/bashshebang) - ✅ WSL/Windows with bash
The hook uses bash-specific features like associative arrays and process substitution, so it requires bash to be available on your system.
- Copy the
pre-commitfile to your git hooks directory:
cp pre-commit .git/hooks/pre-commit- Make sure the hook is executable:
chmod +x .git/hooks/pre-commit- Ensure you have a
.clang-formatfile in your repository root with your preferred formatting rules.
Once installed, the hook runs automatically on every git commit. It will:
- Process only staged files (files added with
git add) - Show a clear status for each operation with colored output:
- ✅ Passed - No changes needed
- ❌ Failed - Files were modified by the hook
- Skipped - No relevant files found
If any files are modified by the hook, the commit will be rejected with exit code 1, allowing you to review the changes before committing again.
Running pre-commit hook
✅ whitespaces...............................................................Passed
✅ tabs......................................................................Passed
❌ clang-format..............................................................Failed
- Files were modified by this hook
The hook operates in the git repository root and:
- Checks for staged files using
git diff --diff-filter=d --cached --name-only - Separates files into general files and C/C++ source files
- Applies whitespace/tab cleanup to general files
- Runs
clang-formatwith--dry-runfirst to check if formatting is needed - If changes are required, applies them and reports the modifications
- Exits with code 1 if any files were modified, preventing the commit