A pre-commit hook repository for C/C++ projects that installs and runs
clang-format and clang-tidy through the
pre-commit framework.
Use cpp-linter-hooks when you want the same C/C++ formatting and linting tools
to run consistently on developer machines and in CI without requiring every
developer to install LLVM tools manually.
clang-format and clang-tidy from one pre-commit repository.--version..clang-format and .clang-tidy configuration files.compile_commands.json for CMake and Meson-style build trees.clang-format dry-run checks, verbose diagnostics, and opt-in
clang-tidy fixes.Compared with mirrors-clang-format,
this project also provides clang-tidy, compile database discovery, explicit
tool-version selection, and richer diagnostics. See the FAQ for the full
comparison.
[!TIP] Using GitHub Actions for CI? Check out cpp-linter-action — our companion GitHub Action that runs the same tools in CI with rich PR reviews, thread comments, step summaries, and file annotations.
Add this configuration to your .pre-commit-config.yaml file:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0 # Use the tag or commit you want
hooks:
- id: clang-format
args: [--style=Google] # Other coding style: LLVM, GNU, Chromium, Microsoft, Mozilla, WebKit.
- id: clang-tidy
args: [--checks='boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,clang-analyzer-*,cppcoreguidelines-*']
To use custom configurations like .clang-format and .clang-tidy:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file] # Loads style from .clang-format file
- id: clang-tidy
args: [--checks=.clang-tidy] # Loads checks from .clang-tidy file
[!TIP] The
revtag (e.g.v1.6.0) is the project version, not the clang tool version. Each release bundles a default version ofclang-formatandclang-tidy— check the release notes to see which tool version a givenrevships with. To pin an exact tool version independently of the project release, use--versionas shown below.
To use specific versions of clang-format and clang-tidy (using Python wheel packages):
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21] # Specifies version
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21] # Specifies version
[!TIP] For production use, always pin the tool version explicitly with
--version(e.g.--version=21) so upgrades tocpp-linter-hooksnever silently change your linter version.
For CMake or Meson projects, clang-tidy works best with a compile_commands.json
file that records the exact compiler flags used for each file. Without it, clang-tidy
may report false positives from missing include paths or wrong compiler flags.
The hook auto-detects compile_commands.json in common build directories (build/,
out/, cmake-build-debug/, _build/) and passes -p <dir> to clang-tidy
automatically — no configuration needed for most projects:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy]
# Auto-detects ./build/compile_commands.json if present
To specify the build directory explicitly:
- id: clang-tidy
args: [--compile-commands=build, --checks=.clang-tidy]
To disable auto-detection (e.g. in a monorepo where auto-detect might pick the wrong database):
- id: clang-tidy
args: [--no-compile-commands, --checks=.clang-tidy]
To see which compile_commands.json the hook is using, add -v:
- id: clang-tidy
args: [--compile-commands=build, -v, --checks=.clang-tidy]
[!NOTE] Generate
compile_commands.jsonwith CMake usingcmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bbuild .or addset(CMAKE_EXPORT_COMPILE_COMMANDS ON)to yourCMakeLists.txt.--compile-commandstakes the directory containingcompile_commands.json, not the file path itself.
clang-format.............................................................Failed
- hook id: clang-format
- files were modified by this hook
Here’s a sample diff showing the formatting applied:
--- a/testing/main.c
+++ b/testing/main.c
@@ -1,3 +1,6 @@
#include <stdio.h>
-int main() {for (;;) break; printf("Hello world!\n");return 0;}
-
+int main() {
+ for (;;) break;
+ printf("Hello world!\n");
+ return 0;
+}
[!NOTE] Use
--dry-runinargsofclang-formatto print instead of changing the format, e.g.:
clang-format.............................................................Failed
- hook id: clang-format
- exit code: 255
main.c:2:11: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:13: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:21: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:28: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:54: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:63: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
clang-tidy...............................................................Failed
- hook id: clang-tidy
- exit code: 1
522 warnings generated.
Suppressed 521 warnings (521 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
/home/runner/work/cpp-linter-hooks/cpp-linter-hooks/testing/main.c:4:13: warning: statement should be inside braces [readability-braces-around-statements]
for (;;)
^
{
[!NOTE] Add
--fixtoargsto automatically apply clang-tidy fixes in place (equivalent to passing-fixto clang-tidy directly). This is opt-in and not the default because auto-fixing can modify source files in unexpected ways. A validcompile_commands.jsonis strongly recommended when using--fix.For cases where compiler errors exist alongside style issues, pass
-fix-errorsdirectly inargsinstead (clang-tidy native flag).
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0 # includes --fix support
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy, --fix]
[!WARNING] When
--fix(or-fix-errors) is active, parallel execution via--jobs/-jis automatically disabled to prevent concurrent writes to the same header file.
[!TIP] For large codebases, if your
pre-commitruns longer than expected, it is highly recommended to addfilesin.pre-commit-config.yamlto limit the scope of the hook. This helps improve performance by reducing the number of files being checked and avoids unnecessary processing. Here's an example configuration:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21]
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$ # Limits to specific dirs and file types
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21]
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$
For clang-tidy, you can also process multiple files in parallel by adding --jobs
or -j:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21, --jobs=4]
[!WARNING] When using
--jobs/-j, avoid sharing options that write to a single output file (for example--export-fixes=fixes.yaml) across parallelclang-tidyinvocations. If you need--export-fixes, ensure each job writes to a unique file path to avoid corrupted or overwritten outputs. Alternatively, if you want to run the hooks manually on only the changed files, you can use the following command:
pre-commit run --files $(git diff --name-only)
This approach ensures that only modified files are checked, further speeding up the linting process during development.
[!NOTE] Use
-vor--verboseinargsto enable verbose output. Forclang-format, it shows the list of processed files. Forclang-tidy, it prints whichcompile_commands.jsonis being used (when auto-detected or explicitly set).
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21, --verbose] # Shows processed files
- id: clang-tidy
args: [--checks=.clang-tidy, --verbose] # Shows which compile_commands.json is used
Two self-contained templates plus quick snippets for other common setups.
files: regex — scoping hooks for speedcompile_commands.json
Bosch Research
MIT ACL
Bazel Contrib
CodSpeed
Jupyter Xeus
Rancher Sandbox
Computational Geography
IMSY
CONVINCE-Project
and many more.
See the cpp-linter hub for the full list of organizations using cpp-linter tools.
cpp-linter-hooks and mirrors-clang-format?| Feature | cpp-linter-hooks | mirrors-clang-format |
|---|---|---|
Supports clang-format and clang-tidy | ✅ (clang-format & clang-tidy) | ✅ (clang-format only) |
| Custom configuration files | ✅ .clang-format, .clang-tidy | ✅ .clang-format |
| Specify tool version | ✅ via --version arg (e.g. --version=21) | ✅ via rev tag (e.g. rev: v21.1.8) |
rev tag meaning | Project version — see release notes for bundled tool version | Equals the clang-format version directly |
| Supports passing format style string | ✅ via --style | ❌ |
| Verbose output | ✅ via --verbose | ❌ |
| Dry-run mode | ✅ via --dry-run | ❌ |
| Auto-fix mode | ✅ via --fix (clang-tidy only) | ❌ |
| Compilation database support | ✅ auto-detect or --compile-commands | ❌ |
We welcome contributions! Whether it's fixing issues, suggesting improvements, or submitting pull requests, your support is greatly appreciated.
This project is licensed under the MIT License.
162 commits
79 commits
16 commits
13 commits
Python
93.4%
Shell
5.7%
A pre-commit hook repository for C/C++ projects that installs and runs
clang-format and clang-tidy through the
pre-commit framework.
Use cpp-linter-hooks when you want the same C/C++ formatting and linting tools
to run consistently on developer machines and in CI without requiring every
developer to install LLVM tools manually.
clang-format and clang-tidy from one pre-commit repository.--version..clang-format and .clang-tidy configuration files.compile_commands.json for CMake and Meson-style build trees.clang-format dry-run checks, verbose diagnostics, and opt-in
clang-tidy fixes.Compared with mirrors-clang-format,
this project also provides clang-tidy, compile database discovery, explicit
tool-version selection, and richer diagnostics. See the FAQ for the full
comparison.
[!TIP] Using GitHub Actions for CI? Check out cpp-linter-action — our companion GitHub Action that runs the same tools in CI with rich PR reviews, thread comments, step summaries, and file annotations.
Add this configuration to your .pre-commit-config.yaml file:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0 # Use the tag or commit you want
hooks:
- id: clang-format
args: [--style=Google] # Other coding style: LLVM, GNU, Chromium, Microsoft, Mozilla, WebKit.
- id: clang-tidy
args: [--checks='boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,clang-analyzer-*,cppcoreguidelines-*']
To use custom configurations like .clang-format and .clang-tidy:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file] # Loads style from .clang-format file
- id: clang-tidy
args: [--checks=.clang-tidy] # Loads checks from .clang-tidy file
[!TIP] The
revtag (e.g.v1.6.0) is the project version, not the clang tool version. Each release bundles a default version ofclang-formatandclang-tidy— check the release notes to see which tool version a givenrevships with. To pin an exact tool version independently of the project release, use--versionas shown below.
To use specific versions of clang-format and clang-tidy (using Python wheel packages):
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21] # Specifies version
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21] # Specifies version
[!TIP] For production use, always pin the tool version explicitly with
--version(e.g.--version=21) so upgrades tocpp-linter-hooksnever silently change your linter version.
For CMake or Meson projects, clang-tidy works best with a compile_commands.json
file that records the exact compiler flags used for each file. Without it, clang-tidy
may report false positives from missing include paths or wrong compiler flags.
The hook auto-detects compile_commands.json in common build directories (build/,
out/, cmake-build-debug/, _build/) and passes -p <dir> to clang-tidy
automatically — no configuration needed for most projects:
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy]
# Auto-detects ./build/compile_commands.json if present
To specify the build directory explicitly:
- id: clang-tidy
args: [--compile-commands=build, --checks=.clang-tidy]
To disable auto-detection (e.g. in a monorepo where auto-detect might pick the wrong database):
- id: clang-tidy
args: [--no-compile-commands, --checks=.clang-tidy]
To see which compile_commands.json the hook is using, add -v:
- id: clang-tidy
args: [--compile-commands=build, -v, --checks=.clang-tidy]
[!NOTE] Generate
compile_commands.jsonwith CMake usingcmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bbuild .or addset(CMAKE_EXPORT_COMPILE_COMMANDS ON)to yourCMakeLists.txt.--compile-commandstakes the directory containingcompile_commands.json, not the file path itself.
clang-format.............................................................Failed
- hook id: clang-format
- files were modified by this hook
Here’s a sample diff showing the formatting applied:
--- a/testing/main.c
+++ b/testing/main.c
@@ -1,3 +1,6 @@
#include <stdio.h>
-int main() {for (;;) break; printf("Hello world!\n");return 0;}
-
+int main() {
+ for (;;) break;
+ printf("Hello world!\n");
+ return 0;
+}
[!NOTE] Use
--dry-runinargsofclang-formatto print instead of changing the format, e.g.:
clang-format.............................................................Failed
- hook id: clang-format
- exit code: 255
main.c:2:11: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:13: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:21: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:28: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:54: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
main.c:2:63: warning: code should be clang-formatted [-Wclang-format-violations]
int main() {for (;;) break; printf("Hello world!\n");return 0;}
^
clang-tidy...............................................................Failed
- hook id: clang-tidy
- exit code: 1
522 warnings generated.
Suppressed 521 warnings (521 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
/home/runner/work/cpp-linter-hooks/cpp-linter-hooks/testing/main.c:4:13: warning: statement should be inside braces [readability-braces-around-statements]
for (;;)
^
{
[!NOTE] Add
--fixtoargsto automatically apply clang-tidy fixes in place (equivalent to passing-fixto clang-tidy directly). This is opt-in and not the default because auto-fixing can modify source files in unexpected ways. A validcompile_commands.jsonis strongly recommended when using--fix.For cases where compiler errors exist alongside style issues, pass
-fix-errorsdirectly inargsinstead (clang-tidy native flag).
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0 # includes --fix support
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy, --fix]
[!WARNING] When
--fix(or-fix-errors) is active, parallel execution via--jobs/-jis automatically disabled to prevent concurrent writes to the same header file.
[!TIP] For large codebases, if your
pre-commitruns longer than expected, it is highly recommended to addfilesin.pre-commit-config.yamlto limit the scope of the hook. This helps improve performance by reducing the number of files being checked and avoids unnecessary processing. Here's an example configuration:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21]
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$ # Limits to specific dirs and file types
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21]
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$
For clang-tidy, you can also process multiple files in parallel by adding --jobs
or -j:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-tidy
args: [--checks=.clang-tidy, --version=21, --jobs=4]
[!WARNING] When using
--jobs/-j, avoid sharing options that write to a single output file (for example--export-fixes=fixes.yaml) across parallelclang-tidyinvocations. If you need--export-fixes, ensure each job writes to a unique file path to avoid corrupted or overwritten outputs. Alternatively, if you want to run the hooks manually on only the changed files, you can use the following command:
pre-commit run --files $(git diff --name-only)
This approach ensures that only modified files are checked, further speeding up the linting process during development.
[!NOTE] Use
-vor--verboseinargsto enable verbose output. Forclang-format, it shows the list of processed files. Forclang-tidy, it prints whichcompile_commands.jsonis being used (when auto-detected or explicitly set).
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v1.6.0
hooks:
- id: clang-format
args: [--style=file, --version=21, --verbose] # Shows processed files
- id: clang-tidy
args: [--checks=.clang-tidy, --verbose] # Shows which compile_commands.json is used
Two self-contained templates plus quick snippets for other common setups.
files: regex — scoping hooks for speedcompile_commands.json
Bosch Research
MIT ACL
Bazel Contrib
CodSpeed
Jupyter Xeus
Rancher Sandbox
Computational Geography
IMSY
CONVINCE-Project
and many more.
See the cpp-linter hub for the full list of organizations using cpp-linter tools.
cpp-linter-hooks and mirrors-clang-format?| Feature | cpp-linter-hooks | mirrors-clang-format |
|---|---|---|
Supports clang-format and clang-tidy | ✅ (clang-format & clang-tidy) | ✅ (clang-format only) |
| Custom configuration files | ✅ .clang-format, .clang-tidy | ✅ .clang-format |
| Specify tool version | ✅ via --version arg (e.g. --version=21) | ✅ via rev tag (e.g. rev: v21.1.8) |
rev tag meaning | Project version — see release notes for bundled tool version | Equals the clang-format version directly |
| Supports passing format style string | ✅ via --style | ❌ |
| Verbose output | ✅ via --verbose | ❌ |
| Dry-run mode | ✅ via --dry-run | ❌ |
| Auto-fix mode | ✅ via --fix (clang-tidy only) | ❌ |
| Compilation database support | ✅ auto-detect or --compile-commands | ❌ |
We welcome contributions! Whether it's fixing issues, suggesting improvements, or submitting pull requests, your support is greatly appreciated.
This project is licensed under the MIT License.
162 commits
79 commits
16 commits
13 commits
Python
93.4%
Shell
5.7%