上下文:
我正在使用一些git-hooks自动在Perl脚本上应用某些格式设置选项。在预提交的钩子上,我使用perltidy清理并重新格式化了脚本。我想检查用户在提交消息上输入了什么内容,如果它为空或等于“中止”,我们要阻止提交并撤消格式修改。
问题:
我删除了git钩子的.sample扩展名,并使其可以使用chmod u+x .git/hooks/commit-msg
执行,但是当我的脚本exit 1
提交时,它并没有像应该的那样停止。
commit-msg
此钩子由git-commit [1]和git-merge [1]调用,可以使用--no-verify选项绕过。它只有一个参数,即保存建议的提交日志消息的文件的名称。以非零状态退出会导致命令中止。
源:https://git-scm.com/docs/githooks#_commit_msg
#!/usr/bin/perl -w
use strict;
use warnings;
# Get the path to the files in which we have the commit message
my $commit_file = $ARGV[0];
# Read the file and extract the commit message (lines which don't start with #)
my @commit_msg;
open(my $fh, "<", "$commit_file");
while (my $line = <$fh>) {
if (substr($line, 0, 1) ne "#") {
push(@commit_msg, $line);
}
}
# Check the message isn't empty or we don't have a "abort" line
my $boolean = 0;
foreach my $line (@commit_msg) {
if ($line ne "abort" && $line ne "") {
$boolean = 1;
}
}
if ($boolean == 0) {
print "We should commit the modifications\n";
exit 0; # Don't prevent commit
}
else {
print "We shouldn't commit the modifications\n";
exit 1; # Prevent commit
}
该脚本是可执行的并且有效!如果在提交某些内容时输入“ abort”,它会显示“我们不应该提交所做的修改”,但提交时将放弃出口1 ...
我希望有人能够提供帮助!我是git-hook的新手,找不到解决方案。也许我错过了Stackoverflow上的一些东西,但没有找到回答此问题的帖子。
最好
Antoine
编辑:
我不使用--no-verify
答案 0 :(得分:3)
当我第一次安装钩子时,我无法使其执行任何事情,但这是因为钩子的底片太多。您的语言老师为避免双重否定而提倡的建议也将帮助您编写软件。挂钩尝试通过否定的测试来检验有效条件,如果行看起来不错,则将$boolean
设置为1,但只有在exit 0
时将$boolean
设置为1(表示成功)。是0。
非描述性名称$boolean
可能是部分原因。您可能在设置它和要产生的退出状态之间失去了预期的含义。此外,只要提交消息的最后一行有效,您的逻辑意图就会失败。
下面的代码以git 2.17.1所需的方式运行。
#! /usr/bin/perl -w
use strict;
use warnings;
die "Usage: $0 commit-log-message\n" unless @ARGV == 1; # (1)
# Get the path to the files in which we have the commit message
my $commit_file = shift; # (2)
# Read the file and extract the commit message (lines which don't start with #)
my $commit_msg = "";
open my $fh, "<", $commit_file or die "$0: open $commit_file: $!"; # (3)
while (<$fh>) { # (4)
next if /^#/; # (5)
$commit_msg .= $_;
}
# Check the message isn't empty or we don't have an "abort" line
my $valid_commit_msg = $commit_msg ne "" && $commit_msg !~ /^abort$/m; # (6)
if ($valid_commit_msg) { # (7)
print "We should commit the modifications\n";
exit 0; # Don't prevent commit
}
else {
print "We shouldn't commit the modifications\n";
exit 1; # Prevent commit
}
(1)是的,git应该在日志消息中提供文件名,但是要进行完整性检查,以防代码被复制或以其他方式安装在错误的钩子中。 / p>
(2)用@ARGV
从shift
中提取参数。
(3)始终,总是,总是检查open
的返回值。请注意,错误消息如果确实失败,则包含出现错误($0
)的程序的名称,试图执行的操作("open $commit_file"
)和错误($!
的程序的名称。 )。养成这个习惯。有一天,它将为您节省很多挫败感。
(4)而不是将线复制到数组中,而是将它们全部连接到一个标量中。使用while (<$fh>) { ... }
查看$_
中的每一行,这是Perl的惯用语,会使代码混乱。
(5),跳过注释行就变得很简单next if /^#/;
。
(6)说您的意思。而不是机制($boolean
)来表达您的意图。您想知道一个提交消息在通过之前是有效的。有效的提交消息必须满足两个条件:
abort
。在Perl中呈现,是
my $valid_commit_msg = $commit_msg ne "" && $commit_msg !~ /^abort$/m;
一些注意事项:
!~
运算符会反转正则表达式匹配的含义, ie ,$commit_msg
必须不包含abort
。/m
开关用于多行模式。它使^
和$
锚在目标中的行的开头和结尾处匹配,而不仅仅是最左边和最右边的字符。 (7)以自然阅读的方式将$valid_commit_msg
用作布尔值。
if ($valid_commit_msg) { ... }
比if ($valid_commit_msg == 0) { ... }
更可取,因为0值是错误的值,重复良好的值是多余的,并且结尾处闲散的值很容易被忽略。
答案 1 :(得分:0)
我认为您脚本中的逻辑是相反的,即单词abort
不会导致退出代码1。
我认为以下方法应该有效:
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
my($commit_msg_file) = @ARGV
or die "usage: $0 <commit message file>\n";
open(my $fh, '<', $commit_msg_file);
my $do_commit;
while (<$fh>) {
# skip comment or empty lines
next if /^#/ || /^\s*$/;
# check for the word "abort" on its own line
last if (/^abort$/);
# at least one non-empty non-comment line detected
$do_commit++;
last;
}
close($fh);
if ($do_commit) {
print "We should commit the modifications\n";
exit 0; # Don't prevent commit
}
print "We shouldn't commit the modifications\n";
exit 1; # Prevent commit