I want to run clang-format on every check in on any edited .cpp and .h file in a git repository and make sure that the "main include file" is on top.
There is a filter option for this in .gitattributes:
*.cpp filter=clang-format-cpp
*.h filter=clang-format-cpp
for which the relevant filter can be locally configured with
git config --global filter.clang-format-cpp.clean 'clang-format -assume-filename=test.cpp'
For clang-format, there is an option IncludeIsMainRegex which will always put the "main include file" on top. E.g. with IncludeIsMainRegex: '(test_?)?$' for a file a.cpp or test_a.cpp, the header a.h will be the main include and hence put on top.
However, when the file is formatted through the git filter/clang-format, this main include is not put on top.
Given
.clang-format:
IncludeIsMainRegex: '(test_?)?$'
IncludeBlocks: Regroup
z.cpp:
#include "z.h"
#include "other.h"
#include <includes.h>
#include <here.h>
Expected
z.cpp:
#include "z.h"
#include "other.h"
#include <here.h>
#include <includes.h>
Result
z.cpp:
#include "other.h"
#include "z.h"
#include <here.h>
#include <includes.h>
The reason is very likely that the file is sent through clang-format with stdin/stdout and therefore clang-format does not know the filename (or rather assumes it's test.cpp) and hence cannot determine the main include.
One alternative approach would be to setup a pre-commit hook and let it correct the file in place upon commit. But having them corrected upon staging is much more streamlined than upon committing.
How can clang-format be integrated in a git workflow to automatically put the main include file on top?
For now I just disabled IncludeIsMainRegex: false and this works stable regardless if clang-format is called on the file or via git filter.