我正在编写一个预提交挂钩。我想对所有扩展名为 .php 的文件运行
php -l
。然而我被困住了。
我需要获取暂存的新/更改文件的列表。应排除已删除的文件。
我尝试过使用
git diff
和 git ls-files
,但我想我需要有人帮忙。
获取相同列表的稍微简洁的方法是:
git diff --cached --name-only --diff-filter=ACM
这将返回需要检查的文件列表。
但是仅仅在工作副本上运行
php -l
可能不是正确的做法。如果您正在进行部分提交,即仅选择当前工作集与提交的 HEAD 之间差异的子集,那么测试将在您的工作集上运行,但将验证您的工作集上从未存在过的提交磁盘。
要正确执行此操作,您应该将整个暂存图像提取到临时区域并在那里执行测试。
rm -rf $TEMPDIR
mkdir -p $TEMPDIR
git checkout-index --prefix=$TEMPDIR/ -af
git diff --cached --name-only --diff-filter=ACM | xargs -n 1 -I '{}' \bin\echo TEMPDIR/'{}' | grep \\.php | xargs -n 1 php -l
请参阅为 Git 构建更好的预提交挂钩以了解另一种实现。
git diff --cached --name-status
将显示暂存内容的摘要,因此您可以轻松排除已删除的文件,例如:
M wt-status.c
D wt-status.h
这表明暂存区(索引)中的 wt-status.c 被修改,wt-status.h 被删除。因此,仅检查未删除的文件:
steve@arise:~/src/git <master>$ git diff --cached --name-status | awk '$1 != "D" { print $2 }'
wt-status.c
wt-status.h
你将不得不跳过额外的麻烦来处理带有空格的文件名(git diff 的 -z 选项和一些更有趣的解析)
这里的答案都不支持带空格的文件名。最好的方法是添加
-z
标志与 xargs -0
组合
git diff --cached --name-only --diff-filter=ACM -z | xargs -0 ...
这是 git 在内置示例中给出的内容(请参阅 .git/hooks/pre-commit.sample)
这是我用于 Perl 检查的内容:
#!/bin/bash
while read st file; do
# skip deleted files
if [ "$st" == 'D' ]; then continue; fi
# do a check only on the perl files
if [[ "$file" =~ "(.pm|.pl)$" ]] && ! perl -c "$file"; then
echo "Perl syntax check failed for file: $file"
exit 1
fi
done < <(git diff --cached --name-status)
对于 PHP,它看起来像这样:
#!/bin/bash
while read st file; do
# skip deleted files
if [ "$st" == 'D' ]; then continue; fi
# do a check only on the php files
if [[ "$file" =~ ".php$" ]] && ! php -l "$file"; then
echo "PHP syntax check failed for file: $file"
exit 1
fi
done < <(git diff --cached --name-status)
modifiedFrontendFiles=$(git diff --cached --name-status --relative=frontend)
if [ -n "$modifiedFrontendFiles" ]; then
npm run lint
npm run lint-css
npm run format
git add .
fi
就我而言,我检查更改是否位于前端文件夹中
eddygeek 的 answer 引用了 .git/hooks/pre-commit.sample
示例。
git diff --cached --name-only --diff-filter=ACM -z | xargs -0 ...
该示例在 Git 2.44(2024 年第 1 季度)中发生了变化:尝试捕获使用潜在不可移植字符的新路径的引入的示例预提交挂钩没有注意到现有路径被“重命名”为这样一个有问题的路径当启用重命名检测时。请参阅commit d9fd71f
(2023 年 11 月 30 日),作者:(由 Junio C Hamano --gitster
-- 合并于 commit 145336e,2023 年 12 月 20 日)
hooks--pre-commit
:重命名时检测非 ASCII 签署人:Julian Prein
当 diff.renames 打开时,diff-filter 将不会返回重命名的文件(或使用 diff.renames=copy 复制的文件),并且此钩子不会捕获潜在的非 ASCII 字符。
使用管道命令 diff-index 而不是瓷器命令,以免受到的影响。
diff.rename
所以代替:
git diff --cached --name-only --diff-filter=A -z $against
您现在可以使用
git diff-index
git diff-index --cached --name-only --diff-filter=A -z $against