我正在编写一个 pre-commit hook。 我想对所有扩展名为 .php 的文件运行 php -l
命令。但是我被卡住了。
我需要获取已暂存的新/更改文件列表,应该排除已删除的文件。
我已经尝试过使用 git diff
和 git ls-files
,但我认为我需要一些帮助。
我正在编写一个 pre-commit hook。 我想对所有扩展名为 .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预提交钩子了解另一种实现方法。
php -l
。这就是我们最终采用的方法。请参见此处:http://github.com/phpbb/phpbb3/blob/develop-olympus/git-tools/hooks/pre-commit - igorwgit show :FILENAME | php -l
。 - Aad Mathijssengit diff --cached --name-status
会显示暂存区中的内容摘要,因此您可以轻松地排除已删除的文件,例如:
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 选项以及更为复杂的解析)。
print $2
部分才能正确运行。解决方法之一:... | awk '$1 != "D" { $1=""; sub(FS,""); print $0 }'
。
另一个注意点:对于文件重命名,git diff
命令会打印旧名称和新名称。如果只需要新名称,请向 git diff
添加 --no-renames
选项,这将把重命名视为删除旧文件并添加新文件。 - Gene Pavlovsky这里提供的回答都不支持包含空格的文件名。最好的方法是结合xargs -0
命令使用-z
标志。
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)
如果使用 -a 标志指定了提交调用,则 git diff --cached 不足够,并且无法确定该标志是否已在钩子中抛出。如果提交的参数可以供钩子检查,那么这将有所帮助。
git status --porcelain | grep -E -v '^[? ]'
- mpersicogit status --porcelain | perl -ane 'print $F[1],qq(\n) if m/^[ACM] /'
是更好的答案。它具有使用 --porcelain 选项的优点,保证永远不会改变。如果 Perl 对您来说太重了,请使用自己的解析器。 - mpersicomodifiedFrontendFiles=$(git diff --cached --name-status --relative=frontend)
if [ -n "$modifiedFrontendFiles" ]; then
npm run lint
npm run lint-css
npm run format
git add .
fi