PATH:
usr
/
libexec
/
git-core
#!/usr/bin/perl # List people who might be interested in a patch. Useful as the argument to # git-send-email --cc-cmd option, and in other situations. # # Usage: git contacts <file | rev-list option> ... use strict; use warnings; use IPC::Open2; my $since = '5-years-ago'; my $min_percent = 10; my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc|Reported-by/i; my %seen; sub format_contact { my ($name, $email) = @_; return "$name <$email>"; } sub parse_commit { my ($commit, $data) = @_; my $contacts = $commit->{contacts}; my $inbody = 0; for (split(/^/m, $data)) { if (not $inbody) { if (/^author ([^<>]+) <(\S+)> .+$/) { $contacts->{format_contact($1, $2)} = 1; } elsif (/^$/) { $inbody = 1; } } elsif (/^$labels_rx:\s+([^<>]+)\s+<(\S+?)>$/o) { $contacts->{format_contact($1, $2)} = 1; } } } sub import_commits { my ($commits) = @_; return unless %$commits; my $pid = open2 my $reader, my $writer, qw(git cat-file --batch); for my $id (keys(%$commits)) { print $writer "$id\n"; my $line = <$reader>; if ($line =~ /^([0-9a-f]{40}) commit (\d+)/) { my ($cid, $len) = ($1, $2); die "expected $id but got $cid\n" unless $id eq $cid; my $data; # cat-file emits newline after data, so read len+1 read $reader, $data, $len + 1; parse_commit($commits->{$id}, $data); } } close $reader; close $writer; waitpid($pid, 0); die "git-cat-file error: $?\n" if $?; } sub get_blame { my ($commits, $source, $from, $ranges) = @_; return unless @$ranges; open my $f, '-|', qw(git blame --porcelain -C), map({"-L$_->[0],+$_->[1]"} @$ranges), '--since', $since, "$from^", '--', $source or die; while (<$f>) { if (/^([0-9a-f]{40}) \d+ \d+ \d+$/) { my $id = $1; $commits->{$id} = { id => $id, contacts => {} } unless $seen{$id}; $seen{$id} = 1; } } close $f; } sub blame_sources { my ($sources, $commits) = @_; for my $s (keys %$sources) { for my $id (keys %{$sources->{$s}}) { get_blame($commits, $s, $id, $sources->{$s}{$id}); } } } sub scan_patches { my ($sources, $id, $f) = @_; my $source; while (<$f>) { if (/^From ([0-9a-f]{40}) Mon Sep 17 00:00:00 2001$/) { $id = $1; $seen{$id} = 1; } next unless $id; if (m{^--- (?:a/(.+)|/dev/null)$}) { $source = $1; } elsif (/^@@ -(\d+)(?:,(\d+))?/ && $source) { my $len = defined($2) ? $2 : 1; push @{$sources->{$source}{$id}}, [$1, $len] if $len; } } } sub scan_patch_file { my ($commits, $file) = @_; open my $f, '<', $file or die "read failure: $file: $!\n"; scan_patches($commits, undef, $f); close $f; } sub parse_rev_args { my @args = @_; open my $f, '-|', qw(git rev-parse --revs-only --default HEAD --symbolic), @args or die; my @revs; while (<$f>) { chomp; push @revs, $_; } close $f; return @revs if scalar(@revs) != 1; return "^$revs[0]", 'HEAD' unless $revs[0] =~ /^-/; return $revs[0], 'HEAD'; } sub scan_rev_args { my ($commits, $args) = @_; my @revs = parse_rev_args(@$args); open my $f, '-|', qw(git rev-list --reverse), @revs or die; while (<$f>) { chomp; my $id = $_; $seen{$id} = 1; open my $g, '-|', qw(git show -C --oneline), $id or die; scan_patches($commits, $id, $g); close $g; } close $f; } sub mailmap_contacts { my ($contacts) = @_; my %mapped; my $pid = open2 my $reader, my $writer, qw(git check-mailmap --stdin); for my $contact (keys(%$contacts)) { print $writer "$contact\n"; my $canonical = <$reader>; chomp $canonical; $mapped{$canonical} += $contacts->{$contact}; } close $reader; close $writer; waitpid($pid, 0); die "git-check-mailmap error: $?\n" if $?; return \%mapped; } if (!@ARGV) { die "No input revisions or patch files\n"; } my (@files, @rev_args); for (@ARGV) { if (-e) { push @files, $_; } else { push @rev_args, $_; } } my %sources; for (@files) { scan_patch_file(\%sources, $_); } if (@rev_args) { scan_rev_args(\%sources, \@rev_args) } my $toplevel = `git rev-parse --show-toplevel`; chomp $toplevel; chdir($toplevel) or die "chdir failure: $toplevel: $!\n"; my %commits; blame_sources(\%sources, \%commits); import_commits(\%commits); my $contacts = {}; for my $commit (values %commits) { for my $contact (keys %{$commit->{contacts}}) { $contacts->{$contact}++; } } $contacts = mailmap_contacts($contacts); my $ncommits = scalar(keys %commits); for my $contact (keys %$contacts) { my $percent = $contacts->{$contact} * 100 / $ncommits; next if $percent < $min_percent; print "$contact\n"; }
[-] git-apply
[edit]
[-] git-fast-export
[edit]
[-] git-get-tar-commit-id
[edit]
[-] git-fast-import
[edit]
[-] git-merge-ours
[edit]
[-] git-fsck-objects
[edit]
[-] git-rev-parse
[edit]
[-] git-http-push
[edit]
[-] git-fsck
[edit]
[-] git-filter-branch
[edit]
[-] git-web--browse
[edit]
[-] git-bugreport
[edit]
[-] git-rebase
[edit]
[-] git-checkout--worker
[edit]
[-] git-rm
[edit]
[-] git-stage
[edit]
[-] git-send-pack
[edit]
[-] git-for-each-ref
[edit]
[-] git-merge-one-file
[edit]
[-] git-pack-redundant
[edit]
[-] git-remote-fd
[edit]
[-] git-mailinfo
[edit]
[-] git-fetch-pack
[edit]
[-] git-update-index
[edit]
[-] git-fmt-merge-msg
[edit]
[-] git-commit-tree
[edit]
[-] git-name-rev
[edit]
[-] git-for-each-repo
[edit]
[-] git-credential-netrc
[edit]
[-] git-help
[edit]
[-] git-index-pack
[edit]
[-] git-check-ignore
[edit]
[-] git-tag
[edit]
[-] git-shell
[edit]
[-] git-merge-resolve
[edit]
[-] git-show-branch
[edit]
[-] git-merge
[edit]
[-] git-submodule
[edit]
[-] git-replace
[edit]
[-] git-status
[edit]
[-] git-bisect
[edit]
[-] git-revert
[edit]
[-] git-difftool
[edit]
[-] git-quiltimport
[edit]
[-] git-check-attr
[edit]
[-] git-restore
[edit]
[-] git-unpack-objects
[edit]
[-] git-mv
[edit]
[-] git-var
[edit]
[-] git-show-index
[edit]
[-] git-push
[edit]
[-] git-unpack-file
[edit]
[-] git-reflog
[edit]
[-] git-config
[edit]
[-] git-diff-tree
[edit]
[-] git-cherry-pick
[edit]
[-] git-version
[edit]
[-] git-remote-ext
[edit]
[-] git-submodule--helper
[edit]
[-] git-credential
[edit]
[-] git-count-objects
[edit]
[-] git-merge-base
[edit]
[-] git
[edit]
[-] git-cherry
[edit]
[-] git-annotate
[edit]
[-] git-describe
[edit]
[-] git-ls-tree
[edit]
[-] git-fsmonitor--daemon
[edit]
[-] git-checkout-index
[edit]
[-] git-pack-refs
[edit]
[-] git-blame
[edit]
[-] git-remote-ftps
[edit]
[-] git-verify-commit
[edit]
[-] git-credential-store
[edit]
[-] git-init
[edit]
[-] git-update-server-info
[edit]
[-] git-request-pull
[edit]
[-] git-init-db
[edit]
[-] git-bundle
[edit]
[-] git-merge-recursive
[edit]
[-] git-repack
[edit]
[-] git-verify-pack
[edit]
[-] git-rerere
[edit]
[-] git-column
[edit]
[-] git-stripspace
[edit]
[+]
..
[-] git-hash-object
[edit]
[-] git-ls-remote
[edit]
[-] git-symbolic-ref
[edit]
[+]
mergetools
[-] git-diff-index
[edit]
[-] git-pull
[edit]
[-] git-write-tree
[edit]
[-] git-whatchanged
[edit]
[-] git-mergetool
[edit]
[-] git-http-fetch
[edit]
[-] git-update-ref
[edit]
[-] git-add
[edit]
[-] git-read-tree
[edit]
[-] git-prune-packed
[edit]
[-] git-check-mailmap
[edit]
[-] git-sh-setup
[edit]
[-] git-sh-i18n
[edit]
[-] git-show-ref
[edit]
[-] git-receive-pack
[edit]
[-] git-merge-file
[edit]
[-] git-mailsplit
[edit]
[-] git-range-diff
[edit]
[-] git-mktag
[edit]
[-] git-remote-ftp
[edit]
[-] git-merge-octopus
[edit]
[-] git-remote
[edit]
[-] git-format-patch
[edit]
[-] git-cat-file
[edit]
[-] git-stash
[edit]
[-] git-upload-archive
[edit]
[-] git-clone
[edit]
[-] git-interpret-trailers
[edit]
[-] git-grep
[edit]
[-] git-contacts
[edit]
[-] git-remote-https
[edit]
[-] git-show
[edit]
[-] git-archive
[edit]
[-] git-pack-objects
[edit]
[-] git-verify-tag
[edit]
[-] git-am
[edit]
[-] git-sh-i18n--envsubst
[edit]
[-] git-http-backend
[edit]
[-] git-clean
[edit]
[-] git-branch
[edit]
[-] git-merge-tree
[edit]
[-] scalar
[edit]
[-] git-credential-cache--daemon
[edit]
[-] git-checkout
[edit]
[-] git-worktree
[edit]
[-] git-mergetool--lib
[edit]
[-] git-fetch
[edit]
[-] git-merge-subtree
[edit]
[-] git-prune
[edit]
[-] git-mktree
[edit]
[-] git-notes
[edit]
[-] git-switch
[edit]
[-] git-merge-index
[edit]
[-] git-sparse-checkout
[edit]
[-] git-commit-graph
[edit]
[-] git-shortlog
[edit]
[-] git-maintenance
[edit]
[-] git-patch-id
[edit]
[-] git-upload-pack
[edit]
[-] git-multi-pack-index
[edit]
[-] git-remote-http
[edit]
[-] git-diff
[edit]
[-] git-diagnose
[edit]
[-] git-rev-list
[edit]
[-] git-gc
[edit]
[-] git-check-ref-format
[edit]
[-] git-diff-files
[edit]
[-] git-hook
[edit]
[-] git-reset
[edit]
[-] git-difftool--helper
[edit]
[-] git-imap-send
[edit]
[-] git-log
[edit]
[-] git-ls-files
[edit]
[-] git-commit
[edit]
[-] git-credential-cache
[edit]