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

时间:2014-04-04 15:13:45

标签: git clang-format

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

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

我有一个基于-output-replacements-xml的潜在解决方案(我将作为答案发布),但这是一个黑客,我觉得这应该更直接。评论/建议,编辑,不同的答案/方法都是受欢迎的。

9 个答案:

答案 0 :(得分:38)

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

我现在所拥有的是

clang-format -style=file -output-replacements-xml | grep -c "<replacement " >/dev/null

这实际上返回了我想要的退出代码的反转,因为如果匹配则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
  1. 获取索引中文件的完整文件名(不包括要删除的文件以及我可能不想处理文件的其他异常情况)
  2. 只保留我要检查格式的文件名(在我的例子中只是c,m和h文件)
  3. 通过xargs将结果运行到“for each”下一个命令
  4. 在所有文件
  5. 上使用-output-replacements-xml选项运行clang-format
  6. 搜索替换(而不是替换),表示clang-format已找到它想要的替换。 (丢弃所有输出,因为XML对用户没有意义。)
  7. 最后一个命令退出1(grep说我们什么也没找到)我们已经完成了,事情还不错。
  8. 如果没有,则显示一条消息并退出1,取消提交。不幸的是,我们没有一种简单的方法可以告诉用户哪个文件是问题,但是他们可以自己运行clang-format并查看。

答案 1 :(得分:6)

run-clang-format是一个围绕clang-format的简单包装器,设计用作钩子或连续集成脚本:它输出差异并以合理的状态退出。

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

run-clang-format example

答案 2 :(得分:4)

我不完全确定您的用例是什么,但请查看git-clang-format(https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang-format)。它基本上为git提供了clang格式的集成,也许这就是你要找的东西。

答案 3 :(得分:3)

使用--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

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

答案 4 :(得分:2)

我稍微调整了comment from phs in this post来提出:

find embedded/ -regex '.*\.\(ino\|cpp\|hpp\|cc\|cxx\|h\)' -exec cat {} \; | diff -u <(find embedded/ -regex '.*\.\(ino\|cpp\|hpp\|cc\|cxx\|h\)' -exec clang-format-3.9 -style=file {} \;) -

那是..

  1. cat所有cpp-ish文件和管道diffdiff将接受stdin,因为我在末尾指定了-
  2. 使用进程替换(<( .. )语法)在这些相同的文件上运行clang-format。不要在这里使用就地格式。这是发送给diff
  3. 的另一半
  4. 如果diff退出但没有输出,则成功!您还可以通过$?检查退出代码 - 它应为零。
  5. 我的CI服务(travis)在bash脚本中运行此行以确保格式正确。我有另一个脚本实际上就地运行格式化程序。这让我想起了一个警告:你必须使用一个可以处理sub(the posix shell does not)的shell。

答案 5 :(得分:1)

我使用git-clang-format和Mike Rhodes的预提交脚本&#39;博客:

#!/bin/python

import subprocess
output = subprocess.check_output(["git", "clang-format", "--diff"])

if output not in ['no modified files to format\n', 'clang-format did not modify any files\n']:
    print "Run git clang-format, then commit.\n"
    exit(1)
else:
    exit(0)

该脚本有一个小错误,因为当没有提交时它不起作用(试图检查尚未存在的HEAD)。要绕过此操作,请使用-n--no-verify选项。

使用-n跳过预提交脚本在您绕过检查时也会有所帮助,因为大型代码库可能需要很长时间。

原始帖子位于:http://www.dx13.co.uk/articles/2015/4/3/Setting-up-git-clang-format.html

答案 6 :(得分:1)

命令行

您可以将 git diffclang-format-diff 一起使用:

$ git diff -U0 --no-color --staged HEAD | clang-format-diff -p1

注意:

  • --staged 仅用于在暂存更改上运行 clang-format-diff
  • 如果要在特定目录上运行此命令,可以将其重写为:
$ git diff -U0 --no-color --staged HEAD -- $PWD/dir1 $PWD/dir2 $PWD/dir3  | clang-format-diff -p1

..和 pre-commit

现在你的预提交可以是这个:

#!/bin/bash

dir_list="$PWD"  # Add the directories you want here
cmd="git diff -U0 --no-color --staged HEAD -- $dir_list | clang-format-diff -p1"

echo ""
echo "Running clang-format on this commit"
echo ""

# Execute the format command
diff=$(eval "$cmd")
if [[ $? -ne 0 ]]
then
    echo "Command failed to execute."
    exit 1
fi

# Print the outcome
if [[ -z "$diff" ]]
then
    echo "Everything is clean"
    exit 0
else
    echo "$diff"
    echo ""
    echo "Commit aborted due to code format inconsistencies."
    exit 1
fi

答案 7 :(得分:0)

在我受到David Ogren's post的启发后,我创建了一个pre-commit钩子,可以处理分阶段的更改。这将确保pre-commit挂钩将对将实际构成提交内容的代码起作用,并且不会被没有上演的clang-format运行所欺骗

#!/bin/bash

files=()
for file in `git diff --cached --name-only --diff-filter=ACMRT | grep -E "\.(cpp|hpp)$"`; do
  if ! cmp -s <(git show :${file}) <(git show :${file}|clang-format); then
    files+=("${file}")
  fi
done

if [ -n "${files}" ]; then
echo Format error within the following files:
printf "%s\n" "${files[@]}"
exit 1
fi

答案 8 :(得分:0)

您可以简单地使用 -n 选项

clang-format -n <file>