Git 预提交挂钩:更改/添加文件

问题描述 投票:0回答:7

我正在编写一个预提交挂钩。我想对所有扩展名为 .php 的文件运行

php -l
。然而我被困住了。

我需要获取暂存的新/更改文件的列表。应排除已删除的文件。

我尝试过使用

git diff
git ls-files
,但我想我需要有人帮忙。

git hook pre-commit-hook pre-commit
7个回答
116
投票

获取相同列表的稍微简洁的方法是:

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 构建更好的预提交挂钩以了解另一种实现。


57
投票

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 选项和一些更有趣的解析)


27
投票

这里的答案都不支持带空格的文件名。最好的方法是添加

-z
标志与
xargs -0

组合
git diff --cached --name-only --diff-filter=ACM -z | xargs -0 ...

这是 git 在内置示例中给出的内容(请参阅 .git/hooks/pre-commit.sample


17
投票

这是我用于 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)

2
投票
如果使用 -a 标志指定提交调用,则 git diff --cached 是不够的,并且无法确定该标志是否已被抛出到挂钩中。如果提交的参数应该可供钩子检查,这将会有所帮助。


1
投票
要了解特定文件夹中的文件已更改,我这样做:

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
就我而言,我检查更改是否位于前端文件夹中


0
投票

eddygeekanswer 引用了 .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 日),作者:

Julian Prein (druckdev)

(由 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

    


© www.soinside.com 2019 - 2024. All rights reserved.