5 use open ':std', OUT => ':utf8';
8 use Getopt::Long qw(:config bundling);
14 'min|min-count|unique|u:i',
15 'max|max-count|show|n:i',
16 'version|V' => sub { Getopt::Long::VersionMessage() },
17 'usage|h' => sub { Getopt::Long::HelpMessage() },
18 'help|man|?' => sub { Getopt::Long::HelpMessage(-verbose => 2) },
24 my $HEADERMATCH = qr/ [a-z]+ (?: (?:-\w+)+ | \ by ) /ix;
30 # strip commit seperator
32 # skip expensive checks without potential identifier
34 # try to parse as UTF-8
35 eval { $_ = decode(utf8 => $_, Encode::FB_CROAK()) };
36 # if invalid, assume it's latin1
37 $_ = decode(cp1252 => $_) if $@;
43 for (reverse split /\n\n/) {
60 push @header, $_ if defined $opt{max};
62 given ($opt{simplify} // 'none') {
63 when (['email', 'authors']) {
67 < [^@>]+ (?: @ | \h?\W? at \W?\h? ) [a-z0-9.-]+ >
71 when (['var', 'vars', '']) {
72 when ($header[0] =~ /[ _-] (?: by | to ) $/imsx) {
76 s{\b (https?)://\S+ }{[$1]}gmsx; # url
77 s{(?: < | \A ) [^@>\s]+ @ [^>]+ (?: > | \Z )}{<...>}igmsx; # address
78 s{\b [0-9]+ \b}{[num]}gmsx; # number
79 s{\b I? [0-9a-f]{40} \b}{[sha1]}gmsx; # hash
82 when (['all', 'contents']) {
85 when (['none', 'no', '0']) {
88 die "Unknown simplify option: '$_'\n";
92 if ($opt{'ignore-case'}) {
93 $_ = lc for $header[0], $header[1] // ();
96 pop @header if not defined $header[-1];
98 push @headers, \@header;
101 next BLOCK if not @headers;
103 if ($opt{debug} and $prefix) {
104 say "infix junk in commit $hash";
108 if (defined $opt{min} or $opt{max}) {
110 my $count = $seen->{ $_->[0] }->{ $_->[1] // '' }++;
111 next if $count >= ($opt{min} // 0) + ($opt{max} || 1);
112 next if $count < ($opt{min} // 0);
114 say $_->[2] // join(': ', @$_);
125 git-grep-footer - Find custom header lines in commit messages
129 F<git> log --pretty=%b%x00 | F<git-grep-footer> [OPTIONS]
133 Filters out header sections near the end of a commit body,
134 a common convention to list custom metadata such as
135 C<Signed-off-by> and C<Acked-by>.
137 Sections are identified by at least one leading keyword containing a dash
144 =item -i, --ignore-case
146 Lowercases everything.
148 =item -s, --simplify[=<rule>]
150 Modifies values to hide specific details.
151 Several different rules are supported:
155 =item I<var> (default)
157 Replaces highly variable contents such as numbers, hashes, and addresses,
158 leaving only exceptional annotations as distinct text.
159 Attributes ending in I<-to> or I<-by> are assumed variable author names
160 and omitted entirely,
161 unless they contain a colon indicating possible attribute exceptions.
165 Filters out author lines following the git signoff convention,
166 i.e. an <email address> optionally preceded by a name.
170 Values will be hidden entirely, so only attribute names remain.
174 =item -u, --unique[=<threshold>]
176 Each match is only shown once,
177 optionally after it has already occurred a given amount of times.
179 =item -n, --show[=<limit>]
181 The original line is given for each match,
182 but simplifications still apply for duplicate determination.
183 Additional samples are optionally given upto the given maximum.
189 Mischa POSLAWSKY <perl@shiar.org>
193 Copyright. All rights reserved.