Git Pre-push 钩子不会在多次检查的情况下中止推送

Posted

技术标签:

【中文标题】Git Pre-push 钩子不会在多次检查的情况下中止推送【英文标题】:Git Pre-push hooks not aborting push in case of more than one checks 【发布时间】:2018-11-02 18:04:04 【问题描述】:

在 git 钩子中 - 我想在推送之前检查 jshint 错误和纱线完整性检查,所以我在 pre-push 中添加了下面。 所以它是这样的 -

    # Pre-push hooks
    # Lint stuff before committing
    grunt jshint eslint tslint
    # Verifies that versions and hashed value of the package contents 
      in the project’s package.json matches that of yarn’s lock file.
    yarn check --integrity
这里如果 jshint 给出错误但如果纱线完整性检查通过,仍然 它允许推动。如果纱线失败,它将中止。 如果我颠倒顺序然后如果纱线检查失败并且如果 jshint 通过, 然后它也会推动。如果 jshint 失败,它将中止。

因此只有在最后一次检查失败时才会推送失败,而在其他情况下它会声明错误但仍会推送它

【问题讨论】:

无耻插件,但您可以查看我的助手git-riff,它允许您为钩子中的每个任务编写单独的脚本并为您处理这种情况。 【参考方案1】:

在这里自我宣传:如果你想很花哨,你可以使用我前段时间写的辅助函数(用于提交挂钩)。

你这样运行它:

set -e

run_check 'flake8' . flake8
run_check 'ESLint' . ./node_modules/eslint/bin/eslint.js frontend/js
exit_test

得到这样的输出:

flake8 OK
ESLint OK

或者如果你不太幸运:

./frontend/tests.py:8:83: E999 SyntaxError: invalid syntax
flake8 FAILED

/home/frax/Programowanie/organizer/organizer2/frontend/js/utils.js
  11:18  error  Parsing error: Unexpected token ;

✖ 1 problem (1 error, 0 warnings)

ESLint FAILED
Some check(s) failed.

exit_test 的退出码是上次检查失败的退出码。当使用set -e 时,它成为整个脚本的退出代码。

代码:

# Use run_check to run groups of independent tests, that should all be run even
# if some of them fail (but you still want to know about failure).

# testing_exit_code variable stores last non-zero exit code of the check, or 0,
# if no check failed so far.

# Important note: using trap prevents set -e from intercepting check failures,
# so it's safe (and recommended) to use -e in testing script.

# Example:

#
#    run_check 'Foo check' . echo Foo
#    run_check 'Bar check' . echo Bar
#    exit_test  # fail if any test failed
#

testing_exit_code=0

function run_check () 
    # Usage: run_check <check name> <working directory> <command> [args...]
    local cmd="$1"
    trap 'testing_exit_code=$?; echo "$cmd FAILED"; return 0' ERR
    local cmd_wd="$2"
    shift 2
    ( cd "$cmd_wd" && "$@" )  # run the command
    echo "$cmd OK"


function exit_test () 
    if (( testing_exit_code != 0 )); then
        echo "Some check(s) failed."
    fi
    exit $testing_exit_code

如果添加一些颜色,输出​​看起来会更好。实际上,我的原始脚本中有它们,但为了简洁和可移植性而省略了它们。如果您有兴趣,我可以单独分享带有颜色的版本。

【讨论】:

【参考方案2】:

这真是一个关于编写脚本的问题。

在 sh/bash 脚本中,一系列命令只是运行这一系列命令:

cmd1
cmd2
cmd3

任何一个命令“失败”都没有关系(返回非零退出状态);脚本继续运行下一个。

脚本的最终退出状态是最后运行的命令的退出状态,除非您提供特定状态:

exit 0

(零表示成功)。

如果您希望在任何命令失败后立即退出,您可以设置-e 选项:

set -e
cmd1
cmd2
cmd3

这是相当粗略的,并不总是正确的做法。请注意,如果 cmd2 失败(退出非零),cmd3 甚至不会启动,但 shell 会以 cmd2 的失败退出状态退出。

为了特别花哨,可以保存每个命令的退出状态:

cmd1; cmd1_status=$?
cmd2; cmd2_status=$?
cmd3; cmd3_status=$?

$? 变量扩展为刚刚运行的命令的退出状态。

当然,现在你必须弄清楚如何处理这三个状态,因为你只能退出其中的一个,但你现在可以退出哪个先失败,如果有的话:

test $cmd1_status != 0 && exit $cmd1_status
test $cmd2_status != 0 && exit $cmd2_status
exit $cmd3_status

现在您的脚本无条件运行所有三个命令,但返回第一个非零失败的状态。如果 cmd1 和 cmd2 都返回零状态,则脚本以 cmd3 的状态退出。

【讨论】:

对于 2 cmnds,test cmd1_status != 0 && exit $cmd1_status test cmd2_status != 0 && exit $cmd2_status 即使最后一个命令失败,它仍然会推送 我上面有两个错别字,我会改正的。同时,如果不是这样,请显示确切的代码(可能剪切并粘贴到原始问题中;记得使用“格式即代码”*** 标记)。

以上是关于Git Pre-push 钩子不会在多次检查的情况下中止推送的主要内容,如果未能解决你的问题,请参考以下文章

如何删除远程 git 钩子?

手写 git hooks 脚本(pre-commitcommit-msg)

【Git Hook】之pre-push

如何在 Perl 脚本之间共享 ENV 变量

通过 husky 在 docker 中运行 pre-commit 和 pre-push 命令

在 Git 钩子中获取提交消息