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

发布于 2024-08-24 21:21:19 字数 145 浏览 10 评论 0原文

我正在编写一个预提交挂钩。我想对所有具有 .php 扩展名的文件运行 php -l 。然而我被困住了。

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

我尝试过使用 git diff 和 git ls-files ,但我想我需要帮助。

I am writing a pre-commit hook. I want to run php -l against all files with .php extension. However I am stuck.

I need to obtain a list of new/changed files that are staged. deleted files should be excluded.

I have tried using git diff and git ls-files, but I think I need a hand here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

再浓的妆也掩不了殇 2024-08-31 21:21:20

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

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 预提交钩子

A slightly neater way of obtaining the same list is:

git diff --cached --name-only --diff-filter=ACM

This will return the list of files that need to be checked.

But just running php -l on your working copy may not be the right thing to do. If you are doing a partial commit i.e. just selecting a subset of the differences between your current working set and the HEAD for the commit, then the test will be run on your working set, but will be certifying a commit that has never existed on your disk.

To do it right you should extract the whole staged image to a temp area and perform the test there .

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

See Building a better pre-commit hook for Git for another implementation.

看海 2024-08-31 21:21:20

git diff --cached --name-status 将显示暂存内容的摘要,因此您可以轻松排除已删除的文件,例如:

M       wt-status.c
D       wt-status.h

这表明 wt-status.c 已被修改并且 wt-status.c 已被修改。 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 选项和一些更有趣的解析)

git diff --cached --name-status will show a summary of what's staged, so you can easily exclude removed files, e.g.:

M       wt-status.c
D       wt-status.h

This indicates that wt-status.c was modified and wt-status.h was removed in the staging area (index). So, to check only files that weren't removed:

steve@arise:~/src/git <master>$ git diff --cached --name-status | awk '$1 != "D" { print $2 }'
wt-status.c
wt-status.h

You will have to jump through extra hoops to deal with filenames with spaces in though (-z option to git diff and some more interesting parsing)

囍孤女 2024-08-31 21:21:20

这里的答案都不支持带空格的文件名。最好的方法是添加 -z 标志与 xargs -0 结合使用,

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

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

None of the answers here support filenames with spaces. The best way for that is to add the -z flag in combination with xargs -0

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

This is what is given by git in built-in samples (see .git/hooks/pre-commit.sample)

倥絔 2024-08-31 21:21:20

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

Here is what I use for my Perl checks:

#!/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)

for PHP it will look like this:

#!/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)
友欢 2024-08-31 21:21:20

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

git diff --cached is not sufficient if the commit call was specified with the -a flag, and there is no way to determine if that flag has been thrown in the hook. It would help if the arguments to commit should be available to the hook for examination.

迷你仙 2024-08-31 21:21:20

为了了解特定文件夹中的文件已更改,我这样做:

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

在我的情况下,我检查更改是否位于前端文件夹中

to understand that the files have changed in a specific folder, I do this:

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

in my case i check that the changes are in the frontend folder

eddygeek答案 引用 .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 -- 合并于 提交 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

eddygeek's answer cites the .git/hooks/pre-commit.sample example.

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

That example just changed with Git 2.44 (Q1 2024): the sample pre-commit hook that tries to catch the introduction of new paths that use potentially non-portable characters did not notice an existing path getting renamed to such a problematic path when rename detection was enabled.

See commit d9fd71f (30 Nov 2023) by Julian Prein (druckdev).
(Merged by Junio C Hamano -- gitster -- in commit 145336e, 20 Dec 2023)

hooks--pre-commit: detect non-ASCII when renaming

Signed-off-by: Julian Prein

When diff.renames is turned on, the diff-filter will not return renamed files (or copied ones with diff.renames=copy) and potential non-ASCII characters would not be caught by this hook.

Use the plumbing command diff-index instead of the porcelain one to not be affected by diff.rename.

So instead of:

git diff --cached --name-only --diff-filter=A -z $against

You now have, using git diff-index instead:

git diff-index --cached --name-only --diff-filter=A -z $against
寂寞花火° 2024-08-31 21:21:20

如果有人正在寻找预推送检查,那么

git diff --name-only @{push}..

可以使用。

例子:

monitored_folder="API/API.Site/Controllers"

changed_files=$(git diff --name-only @{push}..)

for file in $changed_files; do
    if [[ $file == $monitored_folder* ]]; then
        echo "Changes detected in '$monitored_folder'. Aborting push."
        exit 1
    else 
        echo $file;
    fi
done

If anyone is looking for pre-push check, then

git diff --name-only @{push}..

can be used.

Example:

monitored_folder="API/API.Site/Controllers"

changed_files=$(git diff --name-only @{push}..)

for file in $changed_files; do
    if [[ $file == $monitored_folder* ]]; then
        echo "Changes detected in '$monitored_folder'. Aborting push."
        exit 1
    else 
        echo $file;
    fi
done

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文