mirror of
https://https.git.savannah.gnu.org/git/diffutils.git
synced 2026-01-26 15:03:22 +00:00
maint: require that commit messages be of a certain form
* bootstrap.conf (bootstrap_epilogue): Merge from coreutils, so that a local commit hook will now help enforce consistent commit messages. * Makefile.am (check-git-hook-script-sync): New rule, largely copied from coreutils. * scripts/git-hooks/commit-msg: New file, from coreutils, but with adapted list of program names. * scripts/git-hooks/applypatch-msg: New file, from git. * scripts/git-hooks/pre-applypatch: Likewise. * scripts/git-hooks/pre-commit: Likewise.
This commit is contained in:
parent
1a0df4396e
commit
b3def738f3
14
Makefile.am
14
Makefile.am
@ -42,3 +42,17 @@ gen-ChangeLog:
|
||||
ALL_RECURSIVE_TARGETS += distcheck-hook
|
||||
distcheck-hook:
|
||||
$(MAKE) my-distcheck
|
||||
|
||||
# Some of our git hook scripts are supposed to be identical to git's samples.
|
||||
# See if they are still in sync.
|
||||
.PHONY: check-git-hook-script-sync
|
||||
check-git-hook-script-sync:
|
||||
@fail=0; \
|
||||
t=$$(mktemp -d) \
|
||||
&& cd $$t && git init -q && cd .git/hooks \
|
||||
&& for i in pre-commit pre-applypatch applypatch-msg; do \
|
||||
diff -u $(abs_top_srcdir)/scripts/git-hooks/$$i $$i.sample \
|
||||
|| fail=1; \
|
||||
done; \
|
||||
rm -rf $$t; \
|
||||
test $$fail = 0
|
||||
|
||||
@ -129,4 +129,29 @@ bootstrap_post_import_hook()
|
||||
bootstrap_epilogue()
|
||||
{
|
||||
perl -pi -e "s/\@PACKAGE\@/$package/g" README-release
|
||||
|
||||
# Since this is a "GNU" package, replace this line
|
||||
# if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null \
|
||||
# | grep -v 'libtool:' >/dev/null; then
|
||||
# with this:
|
||||
# if true; then
|
||||
# Why? That pipeline searches all files in $(top_srcdir), and if you
|
||||
# happen to have large files (or apparently large sparse files), the
|
||||
# first grep may well run out of memory.
|
||||
perl -pi -e 's/if LC_ALL=C grep .GNU .PACKAGE.*; then/if true; then/' \
|
||||
po/Makefile.in.in
|
||||
|
||||
# Install our git hooks, as long as "cp" accepts the --backup option,
|
||||
# so that we can back up any existing files.
|
||||
case $(cp --help) in *--backup*) backup=1;; *) backup=0;; esac
|
||||
if test $backup = 1; then
|
||||
hooks=$(cd scripts/git-hooks && git ls-files)
|
||||
for f in $hooks; do
|
||||
# If it is identical, skip it.
|
||||
cmp scripts/git-hooks/$f .git/hooks/$f > /dev/null \
|
||||
&& continue
|
||||
cp --backup=numbered scripts/git-hooks/$f .git/hooks
|
||||
chmod a-w .git/hooks/$f
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
15
scripts/git-hooks/applypatch-msg
Executable file
15
scripts/git-hooks/applypatch-msg
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
||||
153
scripts/git-hooks/commit-msg
Executable file
153
scripts/git-hooks/commit-msg
Executable file
@ -0,0 +1,153 @@
|
||||
eval '(exit $?0)' && eval 'exec perl -w "$0" ${1+"$@"}'
|
||||
& eval 'exec perl -w "$0" $argv:q'
|
||||
if 0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
(my $ME = $0) =~ s|.*/||;
|
||||
|
||||
# Emulate Git's choice of the editor for the commit message.
|
||||
chomp (my $editor = `git var GIT_EDITOR`);
|
||||
# And have a sane, minimal fallback in case of weird failures.
|
||||
$editor = "vi" if $? != 0 or $editor =~ /^\s*\z/;
|
||||
|
||||
# Keywords allowed before the colon on the first line of a commit message:
|
||||
# program names and a few general category names.
|
||||
my @valid = qw(
|
||||
diff diff3 cmp sdiff
|
||||
|
||||
gnulib tests maint doc build scripts
|
||||
);
|
||||
my $v_or = join '|', @valid;
|
||||
my $valid_regex = qr/^(?:$v_or)$/;
|
||||
|
||||
# Rewrite the $LOG_FILE (old contents in @$LINE_REF) with an additional
|
||||
# a commented diagnostic "# $ERR" line at the top.
|
||||
sub rewrite($$$)
|
||||
{
|
||||
my ($log_file, $err, $line_ref) = @_;
|
||||
local *LOG;
|
||||
open LOG, '>', $log_file
|
||||
or die "$ME: $log_file: failed to open for writing: $!";
|
||||
print LOG "# $err";
|
||||
print LOG @$line_ref;
|
||||
close LOG
|
||||
or die "$ME: $log_file: failed to rewrite: $!\n";
|
||||
}
|
||||
|
||||
sub re_edit($)
|
||||
{
|
||||
my ($log_file) = @_;
|
||||
|
||||
warn "Interrupt (Ctrl-C) to abort...\n";
|
||||
|
||||
system 'sh', '-c', "$editor $log_file";
|
||||
($? & 127) || ($? >> 8)
|
||||
and die "$ME: $log_file: the editor ($editor) failed, aborting\n";
|
||||
}
|
||||
|
||||
sub bad_first_line($)
|
||||
{
|
||||
my ($line) = @_;
|
||||
|
||||
$line =~ /^[Vv]ersion \d/
|
||||
and return '';
|
||||
|
||||
$line =~ /:/
|
||||
or return 'missing colon on first line of log message';
|
||||
|
||||
$line =~ /\.$/
|
||||
and return 'do not use a period "." at the end of the first line';
|
||||
|
||||
# The token(s) before the colon on the first line must be on our list
|
||||
# Tokens may be space- or comma-separated.
|
||||
(my $pre_colon = $line) =~ s/:.*//;
|
||||
my @word = split (/[ ,]/, $pre_colon);
|
||||
my @bad = grep !/$valid_regex/, @word;
|
||||
@bad
|
||||
and return 'invalid first word(s) of summary line: ' . join (', ', @bad);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
# Given a $LOG_FILE name and a \@LINE buffer,
|
||||
# read the contents of the file into the buffer and analyze it.
|
||||
# If the log message passes muster, return the empty string.
|
||||
# If not, return a diagnostic.
|
||||
sub check_msg($$)
|
||||
{
|
||||
my ($log_file, $line_ref) = @_;
|
||||
|
||||
local *LOG;
|
||||
open LOG, '<', $log_file
|
||||
or return "failed to open for reading: $!";
|
||||
@$line_ref = <LOG>;
|
||||
close LOG;
|
||||
|
||||
my @line = @$line_ref;
|
||||
chomp @line;
|
||||
|
||||
# Don't filter out blank or comment lines; git does that already,
|
||||
# and if we were to ignore them here, it could lead to committing
|
||||
# with lines that start with "#" in the log.
|
||||
|
||||
# Filter out leading blank and comment lines.
|
||||
# while (@line && $line[0] =~ /^(?:#.*|[ \t]*)$/) { shift @line; }
|
||||
|
||||
# Filter out blank and comment lines at EOF.
|
||||
# while (@line && $line[$#line] =~ /^(?:#.*|[ \t]*)$/) { pop @line; }
|
||||
|
||||
@line == 0
|
||||
and return 'no log message';
|
||||
|
||||
my $bad = bad_first_line $line[0];
|
||||
$bad
|
||||
and return $bad;
|
||||
|
||||
# Second line should be blank or not present.
|
||||
2 <= @line && length $line[1]
|
||||
and return 'second line must be empty';
|
||||
|
||||
# Limit line length to allow for the ChangeLog's leading TAB.
|
||||
foreach my $line (@line)
|
||||
{
|
||||
72 < length $line && $line =~ /^[^#]/
|
||||
and return 'line longer than 72';
|
||||
}
|
||||
|
||||
my $buf = join ("\n", @line) . "\n";
|
||||
$buf =~ m!https?://bugzilla\.redhat\.com/show_bug\.cgi\?id=(\d+)!s
|
||||
and return "use shorter http://bugzilla.redhat.com/$1";
|
||||
|
||||
$buf =~ m!https?://debbugs\.gnu\.org/(?:cgi/bugreport\.cgi\?bug=)?(\d+)!s
|
||||
and return "use shorter http://bugs.gnu.org/$1";
|
||||
|
||||
$buf =~ /^ *Signed-off-by:/mi
|
||||
and return q(do not use "Signed-off-by:");
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
{
|
||||
@ARGV == 1
|
||||
or die;
|
||||
|
||||
my $log_file = $ARGV[0];
|
||||
|
||||
while (1)
|
||||
{
|
||||
my @line;
|
||||
my $err = check_msg $log_file, \@line;
|
||||
$err eq ''
|
||||
and last;
|
||||
$err = "$ME: $err\n";
|
||||
warn $err;
|
||||
# Insert the diagnostic as a comment on the first line of $log_file.
|
||||
rewrite $log_file, $err, \@line;
|
||||
re_edit $log_file;
|
||||
|
||||
# Stop if our parent is killed.
|
||||
getppid() == 1
|
||||
and last;
|
||||
}
|
||||
}
|
||||
14
scripts/git-hooks/pre-applypatch
Executable file
14
scripts/git-hooks/pre-applypatch
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
||||
49
scripts/git-hooks/pre-commit
Executable file
49
scripts/git-hooks/pre-commit
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
||||
Loading…
x
Reference in New Issue
Block a user