* [PATCH v3 00/11] Add new git-cc-cmd helper to contrib
@ 2013-04-19 19:30 Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
` (11 more replies)
0 siblings, 12 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Hi,
Here goes another try, I made some changes based on comments, and should be
simpler now. Plus a few improvements. The interdiff will be on the patches, but
only the first one changed substantially.
This script allows you to get a list of relevant persons to Cc when sending a
patch series.
% git cc-cmd v1.8.1.6^^1..v1.8.1.6^^2
"Henrik Grubbström" <grubba@grubba.org> (author: 7%)
junio (signer: 84%, author: 15%)
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com> (author: 30%, signer: 7%)
"Jean-Noël AVILA" <avila.jn@gmail.com> (author: 7%)
Jean-Noel Avila <jn.avila@free.fr> (signer: 7%)
Duy Nguyen <pclouds@gmail.com> (author: 7%)
Michael Haggerty <mhagger@alum.mit.edu> (author: 15%)
Clemens Buchacher <drizzd@aon.at> (author: 7%)
Joshua Jensen <jjensen@workspacewhiz.com> (author: 7%)
Johannes Sixt <j6t@kdbg.org> (signer: 7%)
It find people that might be interesting in a patch, by going back through the
history for each single hunk modified, and finding people that reviewed,
acknowledge, signed, or authored the code the patch is modifying.
It does this by running 'git blame' incrementally on each hunk, and then
parsing the commit message. After gathering all the relevant people, it groups
them to show what exactly was their role when the participated in the
development of the relevant commit, and on how many relevant commits they
participated. They are only displayed if they pass a minimum threshold of
participation.
The code finds the changes in each commit in the list, runs 'git blame'
to see which other commits are relevant to those lines, and then adds
the author and signer to the list.
Finally, it calculates what percentage of the total relevant commits
each person was involved in, and if it passes the threshold, it goes in.
You can also choose to show the commits themselves:
% git cc-cmd --commits v1.8.1.6^^1..v1.8.1.6^^2
9db9eec attr: avoid calling find_basename() twice per path
94bc671 Add directory pattern matching to attributes
82dce99 attr: more matching optimizations from .gitignore
593cb88 exclude: split basename matching code into a separate function
b559263 exclude: split pathname matching code into a separate function
4742d13 attr: avoid searching for basename on every match
f950eb9 rename pathspec_prefix() to common_prefix() and move to dir.[ch]
4a085b1 consolidate pathspec_prefix and common_prefix
d932f4e Rename git_checkattr() to git_check_attr()
2d72174 Extract a function collect_all_attrs()
8cf2a84 Add string comparison functions that respect the ignore_case variable.
407a963 Merge branch 'rr/remote-helper-doc'
ec775c4 attr: Expand macros immediately when encountered.
But wait, there's more: you can also specify a list of patch files, which means
this can be used for git send-emails --cc-cmd option.
Felipe Contreras (11):
Add new git-cc-cmd helper to contrib
contrib: cc-cmd: add option parsing
contrib: cc-cmd: add support for multiple patches
contrib: cc-cmd: add option to show commits
contrib: cc-cmd: add option to parse from committish
contrib: cc-cmd: parse committish like format-patch
contrib: cc-cmd: fix parsing of rev-list args
contrib: cc-cmd: add option to fetch aliases
contrib: cc-cmd: support multiple roles
contrib: cc-cmd: sort by participation
contrib: cc-cmd: ignore chunks with no original lines
contrib/cc-cmd/git-cc-cmd | 258 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 258 insertions(+)
create mode 100755 contrib/cc-cmd/git-cc-cmd
--
1.8.2.1.790.g4588561
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v3 01/11] Add new git-cc-cmd helper to contrib
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:38 ` Felipe Contreras
2013-04-19 22:13 ` Junio C Hamano
2013-04-19 19:30 ` [PATCH v3 02/11] contrib: cc-cmd: add option parsing Felipe Contreras
` (10 subsequent siblings)
11 siblings, 2 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
This script find people that might be interesting in a patch, by going
back through the history for each single hunk modified, and finding
people that reviewed, acknowledge, signed, or authored the code the
patch is modifying.
It does this by running 'git blame' incrementally on each hunk, and then
parsing the commit message. After gathering all the relevant people, it
groups them to show what exactly was their role when the participated in
the development of the relevant commit, and on how many relevant commits
they participated. They are only displayed if they pass a minimum
threshold of participation.
For example:
% git cc-cmd 0001-remote-hg-trivial-cleanups.patch
Felipe Contreras <felipe.contreras@gmail.com> (author: 100%)
Jeff King <peff@peff.net> (signer: 83%)
Max Horn <max@quendi.de> (signer: 16%)
Junio C Hamano <gitster@pobox.com> (signer: 16%)
Thus it can be used for 'git send-email' as a cc-cmd.
Comments-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 131 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
create mode 100755 contrib/cc-cmd/git-cc-cmd
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
new file mode 100755
index 0000000..aa83a1a
--- /dev/null
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -0,0 +1,131 @@
+#!/usr/bin/env ruby
+
+$since = '3-years-ago'
+$min_percent = 5
+
+class Commit
+
+ attr_reader :id, :roles
+
+ def initialize(id)
+ @id = id
+ @roles = []
+ end
+
+ def parse(data)
+ author = msg = nil
+ roles = {}
+ data.each_line do |line|
+ if not msg
+ case line
+ when /^author ([^<>]+) <(\S+)>$/
+ author = $1, $2
+ roles[author] = :author
+ when /^$/
+ msg = true
+ end
+ else
+ if line =~ /^(Signed-off|Reviewed|Acked)-by: ([^<>]+) <(\S+?)>$/
+ person = $2, $3
+ roles[person] = :signer if person != author
+ end
+ end
+ end
+ @roles = roles.map do |person, role|
+ [person, role]
+ end
+ end
+
+end
+
+class Commits
+
+ attr_reader :items
+
+ def initialize()
+ @items = {}
+ end
+
+ def size
+ @items.size
+ end
+
+ def import
+ return if @items.empty?
+ File.popen(%w[git cat-file --batch], 'r+') do |p|
+ p.write(@items.keys.join("\n"))
+ p.close_write
+ p.each do |l|
+ if l =~ /^(\h{40}) commit (\d+)/
+ id, len = $1, $2
+ data = p.read($2.to_i)
+ @items[id].parse(data)
+ end
+ end
+ end
+ end
+
+ def get_blame(source, start, offset, from)
+ return unless source
+ File.popen(['git', 'blame', '--incremental', '-C',
+ '-L', '%u,+%u' % [start, offset],
+ '--since', $since, from + '^',
+ '--', source]) do |p|
+ p.each do |line|
+ if line =~ /^(\h{40})/
+ id = $1
+ @items[id] = Commit.new(id)
+ end
+ end
+ end
+ end
+
+ def from_patch(file)
+ source = nil
+ from = nil
+ File.open(file) do |f|
+ f.each do |line|
+ case line
+ when /^From (\h+) (.+)$/
+ from = $1
+ when /^---\s+(\S+)/
+ source = $1 != '/dev/null' ? $1[2..-1] : nil
+ when /^@@\s-(\d+),(\d+)/
+ get_blame(source, $1, $2, from)
+ end
+ end
+ end
+ end
+
+end
+
+exit 1 if ARGV.size != 1
+
+commits = Commits.new
+commits.from_patch(ARGV[0])
+commits.import
+
+# hash of hashes
+persons = Hash.new { |hash, key| hash[key] = {} }
+
+commits.items.values.each do |commit|
+ commit.roles.each do |person, role|
+ persons[person][role] ||= 0
+ persons[person][role] += 1
+ end
+end
+
+persons.each do |person, roles|
+ roles = roles.map do |role, count|
+ percent = count.to_f * 100 / commits.size
+ next if percent < $min_percent
+ '%s: %u%%' % [role, percent]
+ end.compact
+ next if roles.empty?
+
+ name, email = person
+ # must quote chars?
+ name = '"%s"' % name if name =~ /[^\w \-]/i
+ person = name ? '%s <%s>' % [name, email] : email
+ puts '%s (%s)' % [person, roles.join(', ')]
+end
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 02/11] contrib: cc-cmd: add option parsing
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 03/11] contrib: cc-cmd: add support for multiple patches Felipe Contreras
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index aa83a1a..d78759d 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -1,8 +1,25 @@
#!/usr/bin/env ruby
+require 'optparse'
+
$since = '3-years-ago'
$min_percent = 5
+begin
+ OptionParser.new do |opts|
+ opts.program_name = 'git cc-cmd'
+ opts.banner = 'usage: git cc-cmd [options] <file>'
+
+ opts.on('-p', '--min-percent N', Integer, 'Minium percentage of role participation') do |v|
+ $min_percent = v
+ end
+ opts.on('-d', '--since DATE', 'How far back to search for relevant commits') do |v|
+ $since = v
+ end
+ end.parse!
+rescue OptionParser::InvalidOption
+end
+
class Commit
attr_reader :id, :roles
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 03/11] contrib: cc-cmd: add support for multiple patches
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 02/11] contrib: cc-cmd: add option parsing Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 04/11] contrib: cc-cmd: add option to show commits Felipe Contreras
` (8 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index d78759d..3a9c70e 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -8,7 +8,7 @@ $min_percent = 5
begin
OptionParser.new do |opts|
opts.program_name = 'git cc-cmd'
- opts.banner = 'usage: git cc-cmd [options] <file>'
+ opts.banner = 'usage: git cc-cmd [options] <files>'
opts.on('-p', '--min-percent N', Integer, 'Minium percentage of role participation') do |v|
$min_percent = v
@@ -61,6 +61,7 @@ class Commits
def initialize()
@items = {}
+ @main_commits = {}
end
def size
@@ -91,24 +92,27 @@ class Commits
p.each do |line|
if line =~ /^(\h{40})/
id = $1
- @items[id] = Commit.new(id)
+ @items[id] = Commit.new(id) if not @main_commits.include?(id)
end
end
end
end
- def from_patch(file)
+ def from_patches(files)
source = nil
- from = nil
- File.open(file) do |f|
- f.each do |line|
- case line
- when /^From (\h+) (.+)$/
- from = $1
- when /^---\s+(\S+)/
- source = $1 != '/dev/null' ? $1[2..-1] : nil
- when /^@@\s-(\d+),(\d+)/
- get_blame(source, $1, $2, from)
+ files.each do |file|
+ from = nil
+ File.open(file) do |f|
+ f.each do |line|
+ case line
+ when /^From (\h+) (.+)$/
+ from = $1
+ @main_commits[from] = true
+ when /^---\s+(\S+)/
+ source = $1 != '/dev/null' ? $1[2..-1] : nil
+ when /^@@\s-(\d+),(\d+)/
+ get_blame(source, $1, $2, from)
+ end
end
end
end
@@ -116,10 +120,8 @@ class Commits
end
-exit 1 if ARGV.size != 1
-
commits = Commits.new
-commits.from_patch(ARGV[0])
+commits.from_patches(ARGV)
commits.import
# hash of hashes
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 04/11] contrib: cc-cmd: add option to show commits
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (2 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 03/11] contrib: cc-cmd: add support for multiple patches Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 05/11] contrib: cc-cmd: add option to parse from committish Felipe Contreras
` (7 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Instead of showing the authors and signers, show the commits themselves.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 3a9c70e..c49225f 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -4,6 +4,7 @@ require 'optparse'
$since = '3-years-ago'
$min_percent = 5
+$show_commits = false
begin
OptionParser.new do |opts|
@@ -16,6 +17,9 @@ begin
opts.on('-d', '--since DATE', 'How far back to search for relevant commits') do |v|
$since = v
end
+ opts.on('-c', '--commits[=FORMAT]', [:raw, :full], 'List commits instead of persons') do |v|
+ $show_commits = v || true
+ end
end.parse!
rescue OptionParser::InvalidOption
end
@@ -124,6 +128,20 @@ commits = Commits.new
commits.from_patches(ARGV)
commits.import
+if $show_commits
+ cmd = nil
+ case $show_commits
+ when :raw
+ puts commits.items.keys
+ when :full
+ cmd = %w[git log --patch --no-walk]
+ else
+ cmd = %w[git log --oneline --no-walk]
+ end
+ system(*cmd + commits.items.keys) if cmd
+ exit 0
+end
+
# hash of hashes
persons = Hash.new { |hash, key| hash[key] = {} }
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 05/11] contrib: cc-cmd: add option to parse from committish
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (3 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 04/11] contrib: cc-cmd: add option to show commits Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 06/11] contrib: cc-cmd: parse committish like format-patch Felipe Contreras
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
For example master..feature-a.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index c49225f..aecfa45 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -5,11 +5,13 @@ require 'optparse'
$since = '3-years-ago'
$min_percent = 5
$show_commits = false
+$files = []
+$rev_args = []
begin
OptionParser.new do |opts|
opts.program_name = 'git cc-cmd'
- opts.banner = 'usage: git cc-cmd [options] <files>'
+ opts.banner = 'usage: git cc-cmd [options] <files | rev-list options>'
opts.on('-p', '--min-percent N', Integer, 'Minium percentage of role participation') do |v|
$min_percent = v
@@ -122,10 +124,40 @@ class Commits
end
end
+ def from_rev_args(args)
+ return if args.empty?
+ source = nil
+ File.popen(%w[git rev-list --reverse] + args) do |p|
+ p.each do |e|
+ id = e.chomp
+ @main_commits[id] = true
+ File.popen(%w[git show -C --oneline] + [id]) do |p|
+ p.each do |e|
+ case e
+ when /^---\s+(\S+)/
+ source = $1 != '/dev/null' ? $1[2..-1] : nil
+ when /^@@\s-(\d+),(\d+)/
+ get_blame(source, $1, $2, id)
+ end
+ end
+ end
+ end
+ end
+ end
+
+end
+
+ARGV.each do |e|
+ if File.exists?(e)
+ $files << e
+ else
+ $rev_args << e
+ end
end
commits = Commits.new
-commits.from_patches(ARGV)
+commits.from_patches($files)
+commits.from_rev_args($rev_args)
commits.import
if $show_commits
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 06/11] contrib: cc-cmd: parse committish like format-patch
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (4 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 05/11] contrib: cc-cmd: add option to parse from committish Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 07/11] contrib: cc-cmd: fix parsing of rev-list args Felipe Contreras
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index aecfa45..4bca7f1 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -126,6 +126,20 @@ class Commits
def from_rev_args(args)
return if args.empty?
+
+ revs = []
+
+ File.popen(%w[git rev-parse --revs-only --default=HEAD --symbolic] + args).each do |rev|
+ revs << rev.chomp
+ end
+
+ case revs.size
+ when 1
+ committish = [ '%s..HEAD' % revs[0] ]
+ else
+ committish = revs
+ end
+
source = nil
File.popen(%w[git rev-list --reverse] + args) do |p|
p.each do |e|
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 07/11] contrib: cc-cmd: fix parsing of rev-list args
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (5 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 06/11] contrib: cc-cmd: parse committish like format-patch Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 08/11] contrib: cc-cmd: add option to fetch aliases Felipe Contreras
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
For example '-1'.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 4bca7f1..4fad030 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -23,7 +23,8 @@ begin
$show_commits = v || true
end
end.parse!
-rescue OptionParser::InvalidOption
+rescue OptionParser::InvalidOption => e
+ $rev_args += e.args
end
class Commit
@@ -135,9 +136,11 @@ class Commits
case revs.size
when 1
- committish = [ '%s..HEAD' % revs[0] ]
+ r = revs[0]
+ r = '^' + r if r[0] != '-'
+ args = [ r, 'HEAD' ]
else
- committish = revs
+ args = revs
end
source = nil
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 08/11] contrib: cc-cmd: add option to fetch aliases
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (6 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 07/11] contrib: cc-cmd: fix parsing of rev-list args Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 09/11] contrib: cc-cmd: support multiple roles Felipe Contreras
` (3 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Only the mutt format is supported for now.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 4fad030..200da0d 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -7,6 +7,8 @@ $min_percent = 5
$show_commits = false
$files = []
$rev_args = []
+$get_aliases = false
+$aliases = {}
begin
OptionParser.new do |opts|
@@ -22,11 +24,32 @@ begin
opts.on('-c', '--commits[=FORMAT]', [:raw, :full], 'List commits instead of persons') do |v|
$show_commits = v || true
end
+ opts.on('-a', '--aliases', 'Use aliases') do |v|
+ $get_aliases = v
+ end
end.parse!
rescue OptionParser::InvalidOption => e
$rev_args += e.args
end
+def get_aliases
+ type = %x[git config sendemail.aliasfiletype].chomp
+ return if type != 'mutt'
+ file = %x[git config sendemail.aliasesfile].chomp
+ File.open(File.expand_path(file)) do |f|
+ f.each do |line|
+ if line =~ /^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/
+ key, addresses = $1, $2.split(', ')
+ addresses.each do |address|
+ $aliases[address] = key
+ end
+ end
+ end
+ end
+end
+
+get_aliases if $get_aliases
+
class Commit
attr_reader :id, :roles
@@ -56,6 +79,8 @@ class Commit
end
end
@roles = roles.map do |person, role|
+ address = "%s <%s>" % person
+ person = nil, $aliases[address] if $aliases.include?(address)
[person, role]
end
end
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 09/11] contrib: cc-cmd: support multiple roles
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (7 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 08/11] contrib: cc-cmd: add option to fetch aliases Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 10/11] contrib: cc-cmd: sort by participation Felipe Contreras
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Currently only the roles of 'author' and 'signer' and handler, but now
there's also 'reviewer' and 'acker'.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 200da0d..67a276d 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -50,6 +50,12 @@ end
get_aliases if $get_aliases
+KNOWN_ROLES = {
+ 'Signed-off' => :signer,
+ 'Reviewed' => :reviewer,
+ 'Acked' => :acker,
+}
+
class Commit
attr_reader :id, :roles
@@ -61,27 +67,30 @@ class Commit
def parse(data)
author = msg = nil
- roles = {}
+ # hash of arrays
+ roles = Hash.new { |hash, key| hash[key] = [] }
data.each_line do |line|
if not msg
case line
when /^author ([^<>]+) <(\S+)>$/
author = $1, $2
- roles[author] = :author
+ roles[author] << :author
when /^$/
msg = true
end
else
- if line =~ /^(Signed-off|Reviewed|Acked)-by: ([^<>]+) <(\S+?)>$/
+ role_regex = KNOWN_ROLES.keys.join('|')
+ if line =~ /^(#{role_regex})-by: ([^<>]+) <(\S+?)>$/
person = $2, $3
- roles[person] = :signer if person != author
+ role = KNOWN_ROLES[$1]
+ roles[person] << role if person != author
end
end
end
- @roles = roles.map do |person, role|
+ @roles = roles.map do |person, roles|
address = "%s <%s>" % person
person = nil, $aliases[address] if $aliases.include?(address)
- [person, role]
+ [person, roles]
end
end
@@ -220,9 +229,11 @@ end
persons = Hash.new { |hash, key| hash[key] = {} }
commits.items.values.each do |commit|
- commit.roles.each do |person, role|
- persons[person][role] ||= 0
- persons[person][role] += 1
+ commit.roles.each do |person, roles|
+ roles.each do |role|
+ persons[person][role] ||= 0
+ persons[person][role] += 1
+ end
end
end
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 10/11] contrib: cc-cmd: sort by participation
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (8 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 09/11] contrib: cc-cmd: support multiple roles Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines Felipe Contreras
2013-04-20 1:16 ` [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Duy Nguyen
11 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 67a276d..9a2d2fd 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -237,7 +237,12 @@ commits.items.values.each do |commit|
end
end
-persons.each do |person, roles|
+# sort by number of participations
+count_sort = lambda do |a, b|
+ b[1].values.reduce(:+) <=> a[1].values.reduce(:+)
+end
+
+persons.sort(&count_sort).each do |person, roles|
roles = roles.map do |role, count|
percent = count.to_f * 100 / commits.size
next if percent < $min_percent
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (9 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 10/11] contrib: cc-cmd: sort by participation Felipe Contreras
@ 2013-04-19 19:30 ` Felipe Contreras
2013-04-19 20:04 ` Junio C Hamano
2013-04-20 1:16 ` [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Duy Nguyen
11 siblings, 1 reply; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/cc-cmd/git-cc-cmd | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index 9a2d2fd..02841c4 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -125,7 +125,7 @@ class Commits
end
def get_blame(source, start, offset, from)
- return unless source
+ return unless source and offset
File.popen(['git', 'blame', '--incremental', '-C',
'-L', '%u,+%u' % [start, offset],
'--since', $since, from + '^',
--
1.8.2.1.790.g4588561
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v3 01/11] Add new git-cc-cmd helper to contrib
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
@ 2013-04-19 19:38 ` Felipe Contreras
2013-04-19 22:13 ` Junio C Hamano
1 sibling, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-19 19:38 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Ramkumar Ramachandra, Felipe Contreras
On Fri, Apr 19, 2013 at 2:30 PM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:
> This script find people that might be interesting in a patch, by going
> back through the history for each single hunk modified, and finding
> people that reviewed, acknowledge, signed, or authored the code the
> patch is modifying.
>
> It does this by running 'git blame' incrementally on each hunk, and then
> parsing the commit message. After gathering all the relevant people, it
> groups them to show what exactly was their role when the participated in
> the development of the relevant commit, and on how many relevant commits
> they participated. They are only displayed if they pass a minimum
> threshold of participation.
>
> For example:
>
> % git cc-cmd 0001-remote-hg-trivial-cleanups.patch
> Felipe Contreras <felipe.contreras@gmail.com> (author: 100%)
> Jeff King <peff@peff.net> (signer: 83%)
> Max Horn <max@quendi.de> (signer: 16%)
> Junio C Hamano <gitster@pobox.com> (signer: 16%)
>
> Thus it can be used for 'git send-email' as a cc-cmd.
Here's the interdiff with the previous one:
diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
index c7ecf79..aa83a1a 100755
--- a/contrib/cc-cmd/git-cc-cmd
+++ b/contrib/cc-cmd/git-cc-cmd
@@ -5,40 +5,35 @@ $min_percent = 5
class Commit
- attr_reader :id
- attr_accessor :roles
+ attr_reader :id, :roles
def initialize(id)
@id = id
@roles = []
end
- def self.parse(data)
- id = author = msg = nil
+ def parse(data)
+ author = msg = nil
roles = {}
data.each_line do |line|
if not msg
case line
- when /^commit (.+)$/
- id = $1
when /^author ([^<>]+) <(\S+)>$/
author = $1, $2
- roles[author] = 'author'
+ roles[author] = :author
when /^$/
msg = true
end
else
if line =~ /^(Signed-off|Reviewed|Acked)-by: ([^<>]+) <(\S+?)>$/
person = $2, $3
- roles[person] = 'signer' if person != author
+ roles[person] = :signer if person != author
end
end
end
- roles = roles.map do |person, role|
- address = "%s <%s>" % person
+ @roles = roles.map do |person, role|
[person, role]
end
- [id, roles]
end
end
@@ -57,22 +52,15 @@ class Commits
def import
return if @items.empty?
- format = [ 'commit %H', 'author %an <%ae>', '', '%B' ].join('%n')
- File.popen(['git', 'show', '-z', '-s', '--format=format:' +
format] + @items.keys) do |p|
- p.each("\0") do |data|
- next if data == "\0" # bug in git show?
- id, roles = Commit.parse(data)
- commit = @items[id]
- commit.roles = roles
- end
- end
- end
-
- def each_person_role
- commit_roles = @items.values.map { |commit| commit.roles }.flatten(1)
- commit_roles.group_by { |person, role| person }.each do |person,
commit_roles|
- commit_roles.group_by { |person, role| role }.each do |role,
commit_roles|
- yield person, role, commit_roles.size
+ File.popen(%w[git cat-file --batch], 'r+') do |p|
+ p.write(@items.keys.join("\n"))
+ p.close_write
+ p.each do |l|
+ if l =~ /^(\h{40}) commit (\d+)/
+ id, len = $1, $2
+ data = p.read($2.to_i)
+ @items[id].parse(data)
+ end
end
end
end
@@ -107,34 +95,37 @@ class Commits
end
end
end
- import
end
end
exit 1 if ARGV.size != 1
-commits = Commits.new()
+commits = Commits.new
commits.from_patch(ARGV[0])
+commits.import
# hash of hashes
persons = Hash.new { |hash, key| hash[key] = {} }
-commits.each_person_role do |person, role, count|
- persons[person][role] = count
+commits.items.values.each do |commit|
+ commit.roles.each do |person, role|
+ persons[person][role] ||= 0
+ persons[person][role] += 1
+ end
end
persons.each do |person, roles|
roles = roles.map do |role, count|
percent = count.to_f * 100 / commits.size
next if percent < $min_percent
- "%s: %u%%" % [role, percent]
+ '%s: %u%%' % [role, percent]
end.compact
next if roles.empty?
name, email = person
# must quote chars?
name = '"%s"' % name if name =~ /[^\w \-]/i
- person = name ? "%s <%s>" % [name, email] : email
- puts "%s (%s)" % [person, roles.join(', ')]
+ person = name ? '%s <%s>' % [name, email] : email
+ puts '%s (%s)' % [person, roles.join(', ')]
end
--
Felipe Contreras
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines
2013-04-19 19:30 ` [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines Felipe Contreras
@ 2013-04-19 20:04 ` Junio C Hamano
0 siblings, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2013-04-19 20:04 UTC (permalink / raw)
To: Felipe Contreras; +Cc: git, Ramkumar Ramachandra
Felipe Contreras <felipe.contreras@gmail.com> writes:
> Suggested-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
> ---
> contrib/cc-cmd/git-cc-cmd | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/contrib/cc-cmd/git-cc-cmd b/contrib/cc-cmd/git-cc-cmd
> index 9a2d2fd..02841c4 100755
> --- a/contrib/cc-cmd/git-cc-cmd
> +++ b/contrib/cc-cmd/git-cc-cmd
> @@ -125,7 +125,7 @@ class Commits
> end
>
> def get_blame(source, start, offset, from)
> - return unless source
> + return unless source and offset
I do not think a separate patch at the end is a good idea for a
fix-up like this, even if to give credit to others.
Just squashing it in to the original would help reviewers; that way,
they do not have to wonder "why is this broken" and later notice
"ah, it is fixed at the end".
I do not know if that is an "offset", though. It is the "offset"
for the end of the block relative to its beginning, but people
usually call that the "size" of the block, I think.
> File.popen(['git', 'blame', '--incremental', '-C',
> '-L', '%u,+%u' % [start, offset],
> '--since', $since, from + '^',
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 01/11] Add new git-cc-cmd helper to contrib
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
2013-04-19 19:38 ` Felipe Contreras
@ 2013-04-19 22:13 ` Junio C Hamano
1 sibling, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2013-04-19 22:13 UTC (permalink / raw)
To: Felipe Contreras; +Cc: git, Ramkumar Ramachandra
Felipe Contreras <felipe.contreras@gmail.com> writes:
> This script find people that might be interesting in a patch, by going
> back through the history for each single hunk modified, and finding
> people that reviewed, acknowledge, signed, or authored the code the
> patch is modifying.
>
> It does this by running 'git blame' incrementally on each hunk, and then
> parsing the commit message. After gathering all the relevant people, it
> groups them to show what exactly was their role when the participated in
> the development of the relevant commit, and on how many relevant commits
> they participated. They are only displayed if they pass a minimum
> threshold of participation.
>
> For example:
>
> % git cc-cmd 0001-remote-hg-trivial-cleanups.patch
> Felipe Contreras <felipe.contreras@gmail.com> (author: 100%)
> Jeff King <peff@peff.net> (signer: 83%)
> Max Horn <max@quendi.de> (signer: 16%)
> Junio C Hamano <gitster@pobox.com> (signer: 16%)
Should the contribution weight for each role add up to (close to)
100% if there were no minimum cut-off?
In general, it is not all that clear what these numbers mean. Does
a sign/review on a single commit, no matter what kind of commit it
is or how big it is, count as contribution with the same weight?
I am not saying that the counting criteria needs to be configurable.
It just needs to be explainable to the end users.
> +commits = Commits.new
> +commits.from_patch(ARGV[0])
> +commits.import
> +
> +# hash of hashes
> +persons = Hash.new { |hash, key| hash[key] = {} }
> +
> +commits.items.values.each do |commit|
> + commit.roles.each do |person, role|
> + persons[person][role] ||= 0
> + persons[person][role] += 1
> + end
> +end
> +
> +persons.each do |person, roles|
> + roles = roles.map do |role, count|
> + percent = count.to_f * 100 / commits.size
> + next if percent < $min_percent
> + '%s: %u%%' % [role, percent]
> + end.compact
> + next if roles.empty?
> +
> + name, email = person
> + # must quote chars?
> + name = '"%s"' % name if name =~ /[^\w \-]/i
> + person = name ? '%s <%s>' % [name, email] : email
> + puts '%s (%s)' % [person, roles.join(', ')]
> +end
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/11] Add new git-cc-cmd helper to contrib
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
` (10 preceding siblings ...)
2013-04-19 19:30 ` [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines Felipe Contreras
@ 2013-04-20 1:16 ` Duy Nguyen
2013-04-20 1:34 ` Felipe Contreras
11 siblings, 1 reply; 17+ messages in thread
From: Duy Nguyen @ 2013-04-20 1:16 UTC (permalink / raw)
To: Felipe Contreras; +Cc: Git Mailing List, Junio C Hamano, Ramkumar Ramachandra
On Sat, Apr 20, 2013 at 5:30 AM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:
> This script allows you to get a list of relevant persons to Cc when sending a
> patch series.
>
> % git cc-cmd v1.8.1.6^^1..v1.8.1.6^^2
> "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com> (author: 30%, signer: 7%)
> Duy Nguyen <pclouds@gmail.com> (author: 7%)
You see, I like to cause confusion. These two are the same person.
Maybe you should check based on email only instead.
> "Jean-Noël AVILA" <avila.jn@gmail.com> (author: 7%)
> Jean-Noel Avila <jn.avila@free.fr> (signer: 7%)
And these two are like the same. Perhaps mailmap support will help?
--
Duy
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/11] Add new git-cc-cmd helper to contrib
2013-04-20 1:16 ` [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Duy Nguyen
@ 2013-04-20 1:34 ` Felipe Contreras
0 siblings, 0 replies; 17+ messages in thread
From: Felipe Contreras @ 2013-04-20 1:34 UTC (permalink / raw)
To: Duy Nguyen; +Cc: Git Mailing List, Junio C Hamano, Ramkumar Ramachandra
On Fri, Apr 19, 2013 at 8:16 PM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Sat, Apr 20, 2013 at 5:30 AM, Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
>> This script allows you to get a list of relevant persons to Cc when sending a
>> patch series.
>>
>> % git cc-cmd v1.8.1.6^^1..v1.8.1.6^^2
>> "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com> (author: 30%, signer: 7%)
>> Duy Nguyen <pclouds@gmail.com> (author: 7%)
>
> You see, I like to cause confusion. These two are the same person.
> Maybe you should check based on email only instead.
Should be easy to implement.
>> "Jean-Noël AVILA" <avila.jn@gmail.com> (author: 7%)
>> Jean-Noel Avila <jn.avila@free.fr> (signer: 7%)
>
> And these two are like the same. Perhaps mailmap support will help?
There's already support for user-defined alias
(sendemail.aliasesfile), it shouldn't be too difficult to parse a
.mailmap file too.
Cheers.
--
Felipe Contreras
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2013-04-20 1:34 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-19 19:30 [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 01/11] " Felipe Contreras
2013-04-19 19:38 ` Felipe Contreras
2013-04-19 22:13 ` Junio C Hamano
2013-04-19 19:30 ` [PATCH v3 02/11] contrib: cc-cmd: add option parsing Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 03/11] contrib: cc-cmd: add support for multiple patches Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 04/11] contrib: cc-cmd: add option to show commits Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 05/11] contrib: cc-cmd: add option to parse from committish Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 06/11] contrib: cc-cmd: parse committish like format-patch Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 07/11] contrib: cc-cmd: fix parsing of rev-list args Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 08/11] contrib: cc-cmd: add option to fetch aliases Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 09/11] contrib: cc-cmd: support multiple roles Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 10/11] contrib: cc-cmd: sort by participation Felipe Contreras
2013-04-19 19:30 ` [PATCH v3 11/11] contrib: cc-cmd: ignore chunks with no original lines Felipe Contreras
2013-04-19 20:04 ` Junio C Hamano
2013-04-20 1:16 ` [PATCH v3 00/11] Add new git-cc-cmd helper to contrib Duy Nguyen
2013-04-20 1:34 ` Felipe Contreras
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).