clang格式可以告诉我是否需要格式化更改?

Dav*_*ren 66 git clang-format

有没有办法可以clang-format在报告文件是否符合指定格式的模式下运行?一种干运行模式,它报告是否需要更改,但不进行更改.理想情况下,如果文件需要更改,我希望clang-format只返回非零退出代码.或者,更理想的是,非零退出代码和需要在标准输出上进行更改的文件列表.

我试图将问题保持通用,以便更多人可以回答,但我想要做的是编写一个git pre-commit钩子,它将拒绝任何与预期的.clang格式不匹配的提交.在索引中的文件列表上运行clang-format很容易.但是很难知道clang格式是否真的改变了什么.

我有一个潜在的解决方案-output-replacements-xml(我将作为答案发布),但它是一个黑客,我觉得这应该更直接.欢迎提出意见/建议,编辑,不同的答案/方法.

Dav*_*ren 42

我觉得这样的原因之一应该比它更容易因为-output-replacements-xml本质上给了我想要的答案,它只是不以易于消费的方式给我.但是,由于输出如果不需要替换是非常可预测的,解析输出并不太难.

我现在拥有的是

clang-format -style=file -output-replacements-xml | grep -c "<replacement " >/dev/null
Run Code Online (Sandbox Code Playgroud)

这实际上返回了我想要的退出代码的反转,因为如果匹配则grep返回0,如果没有则返回1.但这很容易处理.

所以我的git pre-commit钩子的相关位是

git diff --cached --name-only --diff-filter=ACMRT |
  grep "\.[cmh]$" |
  xargs -n1 clang-format -style=file -output-replacements-xml |
  grep "<replacement " >/dev/null
if [ $? -ne 1 ]; then 
    echo "Commit did not match clang-format"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)
  1. 获取索引中文件的完整文件名(不包括要删除的文件以及我可能不想处理文件的其他异常情况)
  2. 只保留我想检查格式的文件名(在我的例子中只是c,m和h文件)
  3. 通过xargs运行结果,基本上"为每个"下一个命令
  4. 在所有文件上使用-output-replacements-xml选项运行clang-format
  5. 搜索替换(而不是替换),表示clang-format已找到它想要的替换.(丢弃所有输出,因为XML对用户没有意义.)
  6. 最后一个命令退出1(grep说我们什么也没找到)我们已经完成了,事情还不错.
  7. 如果没有,则显示一条消息并退出1,这将取消提交.不幸的是,我们没有一种简单的方法来告诉用户哪个文件是问题,但是他们可以自己运行clang-format并查看.

  • 我的两分钱:`diff -u <(cat src/*)<(clang-format src/*)`而不是XML (18认同)
  • @phs这是最好的答案! (2认同)
  • 似乎 `clang-format -output-replacements-xml` 输出一些替换,即使 `clang-format -i` 刚刚在文件上运行并且没有更多的替换要进行(结果只是身份替换) . 我不确定在哪种情况下会发生这种情况,但是如果有人发现这想知道为什么答案对他们不起作用,我建议@phs 的建议 (2认同)

小智 18

使用--dry-run-Werror命令行选项。如果任何输入文件的格式不正确,它们将导致 ClangFormat 将任何格式违规输出到 stdout 并返回非零退出状态。

$ clang-format --dry-run --Werror foo.cpp
foo.cpp:129:23: error: code should be clang-formatted [-Wclang-format-violations]
        if (rc <= 0) {
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)

最初来自我的网站:https : //rigtorp.se/notes/clang-format/

  • 对于未来的读者,在 clang-format-10 中添加了“--dry-run”标志。如果您有旧版本,此标志将不起作用。如果您好奇,请查看提交 [6a1f7d6c9ff8228328d0e65b8678a9c6dff49837](https://github.com/llvm/llvm-project/commit/6a1f7d6c9ff8228328d0e65b8678a9c6dff49837)。 (5认同)
  • 更新(6/2):将其更改为官方答案,因为 clang-format (6 年后)现在将此作为官方标志,并且这个问题仍然获得大量流量。 (2认同)

Mat*_*Moy 7

run-clang-format是一个简单的包装,clang-format专门设计为用作钩子或用作连续集成脚本:它输出diff并以明智的状态退出。

主页上给出的示例说明了一切:

run-clang-format示例


gon*_*332 5

命令行

您可以git diff与以下一起使用clang-format-diff

$ git diff -U0 --no-color --staged HEAD | clang-format-diff -p1
Run Code Online (Sandbox Code Playgroud)

笔记:

  • --staged用于clang-format-diff仅在分阶段更改上运行
  • 如果要在特定目录上运行此命令,可以将其重写为:
$ git diff -U0 --no-color --staged HEAD -- $PWD/dir1 $PWD/dir2 $PWD/dir3  | clang-format-diff -p1
Run Code Online (Sandbox Code Playgroud)

..以及pre-commit

现在您的预提交可以是这样的:

$ git diff -U0 --no-color --staged HEAD -- $PWD/dir1 $PWD/dir2 $PWD/dir3  | clang-format-diff -p1
Run Code Online (Sandbox Code Playgroud)