Commit f5492666 authored by Joe Perches's avatar Joe Perches Committed by Linus Torvalds

scripts/get_maintainer.pl: add --git-blame

Julia Lawall suggested that get_maintainers.pl should have the
ability to include signatories of commits that are modified by
a particular patch.

Vegard Nossum did something similar once.
http://lkml.org/lkml/2008/5/29/449

The modified script looks the commits for all lines in the
patch, and includes the "-by:" signatories for those commits.
It uses the same git-min-percent, git-max-maintainers, and
git-min-signatures options.  git-since is ignored.

It can be used independently from the --git default, so
        ./scripts/get_maintainers.pl --nogit --git-blame <patch>
or
        ./scripts/get_maintainers.pl --nogit --git-blame -f <file>
is acceptable.

If used with -f <file>, all lines/commits for the file are
checked.

--git-blame can be slow if used with -f <file>
--git-blame does not work with -f <directory>
Signed-off-by: default avatarJoe Perches <joe@perches.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b61d4a71
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
use strict; use strict;
my $P = $0; my $P = $0;
my $V = '0.17'; my $V = '0.18beta2';
use Getopt::Long qw(:config no_auto_abbrev); use Getopt::Long qw(:config no_auto_abbrev);
...@@ -29,6 +29,7 @@ my $email_git_min_signatures = 1; ...@@ -29,6 +29,7 @@ my $email_git_min_signatures = 1;
my $email_git_max_maintainers = 5; my $email_git_max_maintainers = 5;
my $email_git_min_percent = 5; my $email_git_min_percent = 5;
my $email_git_since = "1-year-ago"; my $email_git_since = "1-year-ago";
my $email_git_blame = 0;
my $output_multiline = 1; my $output_multiline = 1;
my $output_separator = ", "; my $output_separator = ", ";
my $scm = 0; my $scm = 0;
...@@ -68,6 +69,7 @@ if (!GetOptions( ...@@ -68,6 +69,7 @@ if (!GetOptions(
'git-max-maintainers=i' => \$email_git_max_maintainers, 'git-max-maintainers=i' => \$email_git_max_maintainers,
'git-min-percent=i' => \$email_git_min_percent, 'git-min-percent=i' => \$email_git_min_percent,
'git-since=s' => \$email_git_since, 'git-since=s' => \$email_git_since,
'git-blame!' => \$email_git_blame,
'm!' => \$email_maintainer, 'm!' => \$email_maintainer,
'n!' => \$email_usename, 'n!' => \$email_usename,
'l!' => \$email_list, 'l!' => \$email_list,
...@@ -107,8 +109,9 @@ if ($selections == 0) { ...@@ -107,8 +109,9 @@ if ($selections == 0) {
die "$P: Missing required option: email, scm, status, subsystem or web\n"; die "$P: Missing required option: email, scm, status, subsystem or web\n";
} }
if ($email && ($email_maintainer + $email_list + $email_subscriber_list if ($email &&
+ $email_git + $email_git_penguin_chiefs) == 0) { ($email_maintainer + $email_list + $email_subscriber_list +
$email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
usage(); usage();
die "$P: Please select at least 1 email option\n"; die "$P: Please select at least 1 email option\n";
} }
...@@ -150,6 +153,7 @@ close(MAINT); ...@@ -150,6 +153,7 @@ close(MAINT);
## use the filenames on the command line or find the filenames in the patchfiles ## use the filenames on the command line or find the filenames in the patchfiles
my @files = (); my @files = ();
my @range = ();
foreach my $file (@ARGV) { foreach my $file (@ARGV) {
##if $file is a directory and it lacks a trailing slash, add one ##if $file is a directory and it lacks a trailing slash, add one
...@@ -162,13 +166,19 @@ foreach my $file (@ARGV) { ...@@ -162,13 +166,19 @@ foreach my $file (@ARGV) {
push(@files, $file); push(@files, $file);
} else { } else {
my $file_cnt = @files; my $file_cnt = @files;
my $lastfile;
open(PATCH, "<$file") or die "$P: Can't open ${file}\n"; open(PATCH, "<$file") or die "$P: Can't open ${file}\n";
while (<PATCH>) { while (<PATCH>) {
if (m/^\+\+\+\s+(\S+)/) { if (m/^\+\+\+\s+(\S+)/) {
my $filename = $1; my $filename = $1;
$filename =~ s@^[^/]*/@@; $filename =~ s@^[^/]*/@@;
$filename =~ s@\n@@; $filename =~ s@\n@@;
$lastfile = $filename;
push(@files, $filename); push(@files, $filename);
} elsif (m/^\@\@ -(\d+),(\d+)/) {
if ($email_git_blame) {
push(@range, "$lastfile:$1:$2");
}
} }
} }
close(PATCH); close(PATCH);
...@@ -226,6 +236,9 @@ foreach my $file (@files) { ...@@ -226,6 +236,9 @@ foreach my $file (@files) {
recent_git_signoffs($file); recent_git_signoffs($file);
} }
if ($email && $email_git_blame) {
git_assign_blame($file);
}
} }
if ($email) { if ($email) {
...@@ -311,6 +324,7 @@ MAINTAINER field selection options: ...@@ -311,6 +324,7 @@ MAINTAINER field selection options:
--git-max-maintainers => maximum maintainers to add (default: 5) --git-max-maintainers => maximum maintainers to add (default: 5)
--git-min-percent => minimum percentage of commits required (default: 5) --git-min-percent => minimum percentage of commits required (default: 5)
--git-since => git history to use (default: 1-year-ago) --git-since => git history to use (default: 1-year-ago)
--git-blame => use git blame to find modified commits for patch or file
--m => include maintainer(s) if any --m => include maintainer(s) if any
--n => include name 'Full Name <addr\@domain.tld>' --n => include name 'Full Name <addr\@domain.tld>'
--l => include list(s) if any --l => include list(s) if any
...@@ -333,13 +347,15 @@ Other options: ...@@ -333,13 +347,15 @@ Other options:
Notes: Notes:
Using "-f directory" may give unexpected results: Using "-f directory" may give unexpected results:
Used with "--git", git signators for _all_ files in and below Used with "--git", git signators for _all_ files in and below
directory are examined as git recurses directories. directory are examined as git recurses directories.
Any specified X: (exclude) pattern matches are _not_ ignored. Any specified X: (exclude) pattern matches are _not_ ignored.
Used with "--nogit", directory is used as a pattern match, Used with "--nogit", directory is used as a pattern match,
no individual file within the directory or subdirectory no individual file within the directory or subdirectory
is matched. is matched.
Used with "--git-blame", does not iterate all files in directory
Using "--git-blame" is slow and may add old committers and authors
that are no longer active maintainers to the output.
EOT EOT
} }
...@@ -449,17 +465,22 @@ sub push_email_address { ...@@ -449,17 +465,22 @@ sub push_email_address {
my ($email_address) = @_; my ($email_address) = @_;
my $email_name = ""; my $email_name = "";
if ($email_maintainer) {
if ($email_address =~ m/([^<]+)<(.*\@.*)>$/) { if ($email_address =~ m/([^<]+)<(.*\@.*)>$/) {
$email_name = $1; $email_name = $1;
$email_address = $2; $email_address = $2;
} if ($email_usename) {
if ($email_maintainer) {
if ($email_usename && $email_name) {
push(@email_to, format_email($email_name, $email_address)); push(@email_to, format_email($email_name, $email_address));
} else { } else {
push(@email_to, $email_address); push(@email_to, $email_address);
} }
} elsif ($email_address =~ m/<(.+)>/) {
$email_address = $1;
push(@email_to, $email_address);
} else {
push(@email_to, $email_address);
}
} }
} }
...@@ -545,20 +566,79 @@ sub recent_git_signoffs { ...@@ -545,20 +566,79 @@ sub recent_git_signoffs {
last; last;
} }
} }
if ($line =~ m/(.+)<(.+)>/) { push_email_address($line);
my $git_name = $1; }
my $git_addr = $2; }
if ($email_usename) {
push(@email_to, format_email($git_name, $git_addr)); sub save_commits {
} else { my ($cmd, @commits) = @_;
push(@email_to, $git_addr); my $output;
my @lines = ();
$output = `${cmd}`;
@lines = split("\n", $output);
foreach my $line (@lines) {
if ($line =~ m/^(\w+) /) {
push (@commits, $1);
}
}
return @commits;
}
sub git_assign_blame {
my ($file) = @_;
my @lines = ();
my @commits = ();
my $cmd;
my $output;
my %hash;
my $total_sign_offs;
my $count;
if (@range) {
foreach my $file_range_diff (@range) {
next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
my $diff_file = $1;
my $diff_start = $2;
my $diff_length = $3;
next if (!("$file" eq "$diff_file"));
$cmd = "git blame -l -L $diff_start,+$diff_length $file\n";
@commits = save_commits($cmd, @commits);
} }
} elsif ($line =~ m/<(.+)>/) {
my $git_addr = $1;
push(@email_to, $git_addr);
} else { } else {
push(@email_to, $line); if (-f $file) {
$cmd = "git blame -l $file\n";
@commits = save_commits($cmd, @commits);
}
}
$total_sign_offs = 0;
@commits = uniq(@commits);
foreach my $commit (@commits) {
$cmd = "git log -1 ${commit}";
$cmd .= " | grep -Ei \"^[-_ a-z]+by:.*\\\@.*\$\"";
if (!$email_git_penguin_chiefs) {
$cmd .= " | grep -Ev \"${penguin_chiefs}\"";
}
$cmd .= " | cut -f2- -d\":\"";
$output = `${cmd}`;
$output =~ s/^\s*//gm;
@lines = split("\n", $output);
$hash{$_}++ for @lines;
$total_sign_offs += @lines;
} }
$count = 0;
foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
my $sign_offs = $hash{$line};
$count++;
last if ($sign_offs < $email_git_min_signatures ||
$count > $email_git_max_maintainers ||
$sign_offs * 100 / $total_sign_offs < $email_git_min_percent);
push_email_address($line);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment