尝试创建一个 pre-commit 钩子,检查索引中的文件是否格式正确。

huangapple go评论57阅读模式
英文:

Trying to make a pre-commit hook that checks if files in index are formatted correctly

问题

我一直在尝试创建一个预提交挂钩,用于检查索引中的文件是否格式正确。我已经尝试了很多方法,但无法让grep正常工作。这是我当前的代码:

for FILE in $(git diff --cached --name-only)
do
    if [[ "$FILE" =~ \.(c|h|cpp|cc)$ ]]; then
        exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE | grep -c "violations"
    fi
done

我期望它会打印具有格式问题的文件数量(实际上我想搜索字符串"-Wclang-format-violations",但为了测试,我简化了它)。

如果我将clang-format的输出重定向到文件,违规内容将正确打印到该文件中。

exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE &> temp.txt

然后,如果我从命令行上运行grep命令,它也可以正常工作。

grep -c violations temp.txt

我还尝试从脚本中对文件使用grep,但由于某种原因,它也没有产生任何输出(尽管我更希望不必创建文件)。

exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE &> temp.txt
grep -c violations temp.txt

我做错了什么?我原以为我最多只需要半个小时就能让它正常工作。

英文:

I've been trying to make a pre-commit hook that checks if files in the index are formatted correctly. I've tried so many things already but I just can't get the grep to work correctly. This is my code right now:

for FILE in $(git diff --cached --name-only)
do
    if [[ "$FILE" =~ \.(c|h|cpp|cc)$ ]]; then
        exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE | grep -c "violations"
	fi
done

I expect it to print the number of files that have formatting issues (I actually want to search for the string -Wclang-format-violations but I simplified it for testing).

If I &> the clang-format output to a file the violations correctly printed to that file.

exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE &> temp.txt

If I then run grep from the command line on that file it works.

grep -c violations temp.txt

I also tried grep on the file from the script but for some reason that didn't produce any output either (though I would prefer to not have to create a file).

exec C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror $FILE &> temp.txt
grep -c violations temp.txt

What am I doing wrong? I thought I would get this to work in half an hour at most.

答案1

得分: 1

The problem with grep is that you're not redirecting stderr, only stdout. (In your redirection to a file, you are redirecting stderr as well, with >&). To capture stderr in the pipe, use |&.


However, you have a mismatch between what's staged to be committed and what you're looking at. In git, a file isn't staged to be committed, but its contents are. That means that you can stage - for example - part of a file's contents to be committed. The file's contents in the working directory thus would not match what is staged.

Here's a concrete example:

echo "hello" > hello_world.txt
git add hello_world.txt
echo "world" >> hello_world.txt

At this point, the contents staged in the index (from the git add on line 2) are hello. But the file contains hello world on disk.

git status will show the file both as staged and modified:

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   hello_world.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   hello_world.txt

If you were to run git commit now, only the hello would be committed, not the file as it exists on disk.


That means that you want to look at the staged contents of the file -- which is what will actually be committed -- not just the file on disk. Otherwise, you may get false positives or negatives.

To handle this case, you can pass what's staged to clang-format using the git show command. (git show :filename will output the staged contents of filename.)

Try this:

for FILE in $(git diff --cached --name-only)
do
    if [[ "$FILE" =~ \.(c|h|cpp|cc)$ ]]; then
        git cat-file --filters ":${FILE}" | C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror --assume-filename="${FILE}" |&amp; grep -c grep -c "-Wclang-format-violations"
    fi
done
英文:

The problem with grep is that you're not redirecting stderr, only stdout. (In your redirection to a file, you are redirecting stderr as well, with &gt;&amp;.) To capture stderr in the pipe, use |&amp;.


However you have a mismatch between what's staged to be committed and what you're looking at. In git, a file isn't staged to be committed, but its contents are. That means that you can stage - for example - part of a files contents to be committed. The file's contents in the working directory thus would not match what is staged.

Here's a concrete example:

echo &quot;hello&quot; &gt; hello_world.txt
git add hello_world.txt
echo &quot;world&quot; &gt;&gt; hello_world.txt

At this point, the contents staged in the index (from the git add on line 2) are hello. But the file contains hello world on disk.

git status will show the file both as staged and modified:

Changes to be committed:
  (use &quot;git rm --cached &lt;file&gt;...&quot; to unstage)
	new file:   hello_world.txt

Changes not staged for commit:
  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)
  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)
	modified:   hello_world.txt

If you were to run git commit now, only the hello would be committed, not the file as it exists on disk.


That means that you want to look at the staged contents of the file -- which is what will actually be committed -- not just the file on disk. Otherwise you may get false positives or negatives.

To handle this case, you can pass what's staged to clang-format using the git show command. (git show :filename will output the staged contents of filename.)

Try this:

for FILE in $(git diff --cached --name-only)
do
    if [[ &quot;$FILE&quot; =~ \.(c|h|cpp|cc)$ ]]; then
        git cat-file --filters &quot;:${FILE}&quot; | C:/dev/uct/clang-format-15.0.3.exe --dry-run -Werror --assume-filename=&quot;${FILE}&quot; |&amp; grep -c grep -c &quot;\-Wclang\-format\-violations&quot;
    fi
done

huangapple
  • 本文由 发表于 2023年2月14日 00:50:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75438881.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定