Merge branch 'jc/fmt-merge-msg-people'
The "fmt-merge-msg" command learns to list the primary contributors involved in the side topic you are merging. * jc/fmt-merge-msg-people: fmt-merge-msg: show those involved in a merged series
This commit is contained in:
@ -27,6 +27,8 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
|
|||||||
merge_log_config = DEFAULT_MERGE_LOG_LEN;
|
merge_log_config = DEFAULT_MERGE_LOG_LEN;
|
||||||
} else if (!strcmp(key, "merge.branchdesc")) {
|
} else if (!strcmp(key, "merge.branchdesc")) {
|
||||||
use_branch_desc = git_config_bool(key, value);
|
use_branch_desc = git_config_bool(key, value);
|
||||||
|
} else {
|
||||||
|
return git_default_config(key, value, cb);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -180,6 +182,101 @@ static void add_branch_desc(struct strbuf *out, const char *name)
|
|||||||
strbuf_release(&desc);
|
strbuf_release(&desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define util_as_integral(elem) ((intptr_t)((elem)->util))
|
||||||
|
|
||||||
|
static void record_person(int which, struct string_list *people,
|
||||||
|
struct commit *commit)
|
||||||
|
{
|
||||||
|
char name_buf[MAX_GITNAME], *name, *name_end;
|
||||||
|
struct string_list_item *elem;
|
||||||
|
const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
|
||||||
|
|
||||||
|
name = strstr(commit->buffer, field);
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
name += strlen(field);
|
||||||
|
name_end = strchrnul(name, '<');
|
||||||
|
if (*name_end)
|
||||||
|
name_end--;
|
||||||
|
while (isspace(*name_end) && name <= name_end)
|
||||||
|
name_end--;
|
||||||
|
if (name_end < name || name + MAX_GITNAME <= name_end)
|
||||||
|
return;
|
||||||
|
memcpy(name_buf, name, name_end - name + 1);
|
||||||
|
name_buf[name_end - name + 1] = '\0';
|
||||||
|
|
||||||
|
elem = string_list_lookup(people, name_buf);
|
||||||
|
if (!elem) {
|
||||||
|
elem = string_list_insert(people, name_buf);
|
||||||
|
elem->util = (void *)0;
|
||||||
|
}
|
||||||
|
elem->util = (void*)(util_as_integral(elem) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
|
||||||
|
{
|
||||||
|
const struct string_list_item *a = a_, *b = b_;
|
||||||
|
return util_as_integral(b) - util_as_integral(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_people_count(struct strbuf *out, struct string_list *people)
|
||||||
|
{
|
||||||
|
if (people->nr == 1)
|
||||||
|
strbuf_addf(out, "%s", people->items[0].string);
|
||||||
|
else if (people->nr == 2)
|
||||||
|
strbuf_addf(out, "%s (%d) and %s (%d)",
|
||||||
|
people->items[0].string,
|
||||||
|
(int)util_as_integral(&people->items[0]),
|
||||||
|
people->items[1].string,
|
||||||
|
(int)util_as_integral(&people->items[1]));
|
||||||
|
else if (people->nr)
|
||||||
|
strbuf_addf(out, "%s (%d) and others",
|
||||||
|
people->items[0].string,
|
||||||
|
(int)util_as_integral(&people->items[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void credit_people(struct strbuf *out,
|
||||||
|
struct string_list *them,
|
||||||
|
int kind)
|
||||||
|
{
|
||||||
|
const char *label;
|
||||||
|
const char *me;
|
||||||
|
|
||||||
|
if (kind == 'a') {
|
||||||
|
label = "\nBy ";
|
||||||
|
me = git_author_info(IDENT_NO_DATE);
|
||||||
|
} else {
|
||||||
|
label = "\nvia ";
|
||||||
|
me = git_committer_info(IDENT_NO_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!them->nr ||
|
||||||
|
(them->nr == 1 &&
|
||||||
|
me &&
|
||||||
|
(me = skip_prefix(me, them->items->string)) != NULL &&
|
||||||
|
skip_prefix(me, " <")))
|
||||||
|
return;
|
||||||
|
strbuf_addstr(out, label);
|
||||||
|
add_people_count(out, them);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_people_info(struct strbuf *out,
|
||||||
|
struct string_list *authors,
|
||||||
|
struct string_list *committers)
|
||||||
|
{
|
||||||
|
if (authors->nr)
|
||||||
|
qsort(authors->items,
|
||||||
|
authors->nr, sizeof(authors->items[0]),
|
||||||
|
cmp_string_list_util_as_integral);
|
||||||
|
if (committers->nr)
|
||||||
|
qsort(committers->items,
|
||||||
|
committers->nr, sizeof(committers->items[0]),
|
||||||
|
cmp_string_list_util_as_integral);
|
||||||
|
|
||||||
|
credit_people(out, authors, 'a');
|
||||||
|
credit_people(out, committers, 'c');
|
||||||
|
}
|
||||||
|
|
||||||
static void shortlog(const char *name,
|
static void shortlog(const char *name,
|
||||||
struct origin_data *origin_data,
|
struct origin_data *origin_data,
|
||||||
struct commit *head,
|
struct commit *head,
|
||||||
@ -190,6 +287,8 @@ static void shortlog(const char *name,
|
|||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
struct object *branch;
|
struct object *branch;
|
||||||
struct string_list subjects = STRING_LIST_INIT_DUP;
|
struct string_list subjects = STRING_LIST_INIT_DUP;
|
||||||
|
struct string_list authors = STRING_LIST_INIT_DUP;
|
||||||
|
struct string_list committers = STRING_LIST_INIT_DUP;
|
||||||
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
|
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
const unsigned char *sha1 = origin_data->sha1;
|
const unsigned char *sha1 = origin_data->sha1;
|
||||||
@ -199,7 +298,6 @@ static void shortlog(const char *name,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
setup_revisions(0, NULL, rev, NULL);
|
setup_revisions(0, NULL, rev, NULL);
|
||||||
rev->ignore_merges = 1;
|
|
||||||
add_pending_object(rev, branch, name);
|
add_pending_object(rev, branch, name);
|
||||||
add_pending_object(rev, &head->object, "^HEAD");
|
add_pending_object(rev, &head->object, "^HEAD");
|
||||||
head->object.flags |= UNINTERESTING;
|
head->object.flags |= UNINTERESTING;
|
||||||
@ -208,10 +306,15 @@ static void shortlog(const char *name,
|
|||||||
while ((commit = get_revision(rev)) != NULL) {
|
while ((commit = get_revision(rev)) != NULL) {
|
||||||
struct pretty_print_context ctx = {0};
|
struct pretty_print_context ctx = {0};
|
||||||
|
|
||||||
/* ignore merges */
|
if (commit->parents && commit->parents->next) {
|
||||||
if (commit->parents && commit->parents->next)
|
/* do not list a merge but count committer */
|
||||||
|
record_person('c', &committers, commit);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (!count)
|
||||||
|
/* the 'tip' committer */
|
||||||
|
record_person('c', &committers, commit);
|
||||||
|
record_person('a', &authors, commit);
|
||||||
count++;
|
count++;
|
||||||
if (subjects.nr > limit)
|
if (subjects.nr > limit)
|
||||||
continue;
|
continue;
|
||||||
@ -226,6 +329,7 @@ static void shortlog(const char *name,
|
|||||||
string_list_append(&subjects, strbuf_detach(&sb, NULL));
|
string_list_append(&subjects, strbuf_detach(&sb, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_people_info(out, &authors, &committers);
|
||||||
if (count > limit)
|
if (count > limit)
|
||||||
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
|
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
|
||||||
else
|
else
|
||||||
@ -246,6 +350,8 @@ static void shortlog(const char *name,
|
|||||||
rev->commits = NULL;
|
rev->commits = NULL;
|
||||||
rev->pending.nr = 0;
|
rev->pending.nr = 0;
|
||||||
|
|
||||||
|
string_list_clear(&authors, 0);
|
||||||
|
string_list_clear(&committers, 0);
|
||||||
string_list_clear(&subjects, 0);
|
string_list_clear(&subjects, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,15 +35,18 @@ test_expect_success setup '
|
|||||||
|
|
||||||
echo "l3" >two &&
|
echo "l3" >two &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
git commit -a -m "Left #3" &&
|
GIT_COMMITTER_NAME="Another Committer" \
|
||||||
|
GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #3" &&
|
||||||
|
|
||||||
echo "l4" >two &&
|
echo "l4" >two &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
git commit -a -m "Left #4" &&
|
GIT_COMMITTER_NAME="Another Committer" \
|
||||||
|
GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #4" &&
|
||||||
|
|
||||||
echo "l5" >two &&
|
echo "l5" >two &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
git commit -a -m "Left #5" &&
|
GIT_COMMITTER_NAME="Another Committer" \
|
||||||
|
GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #5" &&
|
||||||
git tag tag-l5 &&
|
git tag tag-l5 &&
|
||||||
|
|
||||||
git checkout right &&
|
git checkout right &&
|
||||||
@ -99,6 +102,8 @@ test_expect_success '[merge] summary/log configuration' '
|
|||||||
cat >expected <<-EOF &&
|
cat >expected <<-EOF &&
|
||||||
Merge branch ${apos}left${apos}
|
Merge branch ${apos}left${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left:
|
* left:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -144,6 +149,8 @@ test_expect_success 'merge.log=3 limits shortlog length' '
|
|||||||
cat >expected <<-EOF &&
|
cat >expected <<-EOF &&
|
||||||
Merge branch ${apos}left${apos}
|
Merge branch ${apos}left${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left: (5 commits)
|
* left: (5 commits)
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -159,6 +166,8 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
|
|||||||
cat >expected <<-EOF &&
|
cat >expected <<-EOF &&
|
||||||
Merge branch ${apos}left${apos}
|
Merge branch ${apos}left${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left:
|
* left:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -181,6 +190,8 @@ test_expect_success '--log=3 limits shortlog length' '
|
|||||||
cat >expected <<-EOF &&
|
cat >expected <<-EOF &&
|
||||||
Merge branch ${apos}left${apos}
|
Merge branch ${apos}left${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left: (5 commits)
|
* left: (5 commits)
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -196,6 +207,8 @@ test_expect_success '--log=5 shows all 5 commits' '
|
|||||||
cat >expected <<-EOF &&
|
cat >expected <<-EOF &&
|
||||||
Merge branch ${apos}left${apos}
|
Merge branch ${apos}left${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left:
|
* left:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -225,6 +238,8 @@ test_expect_success 'fmt-merge-msg -m' '
|
|||||||
cat >expected.log <<-EOF &&
|
cat >expected.log <<-EOF &&
|
||||||
Sync with left
|
Sync with left
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* ${apos}left${apos} of $(pwd):
|
* ${apos}left${apos} of $(pwd):
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -256,6 +271,8 @@ test_expect_success 'setup: expected shortlog for two branches' '
|
|||||||
cat >expected <<-EOF
|
cat >expected <<-EOF
|
||||||
Merge branches ${apos}left${apos} and ${apos}right${apos}
|
Merge branches ${apos}left${apos} and ${apos}right${apos}
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left:
|
* left:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -379,6 +396,8 @@ test_expect_success 'merge-msg two tags' '
|
|||||||
Common #2
|
Common #2
|
||||||
Common #1
|
Common #1
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* tag ${apos}tag-l5${apos}:
|
* tag ${apos}tag-l5${apos}:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
@ -407,6 +426,8 @@ test_expect_success 'merge-msg tag and branch' '
|
|||||||
Common #2
|
Common #2
|
||||||
Common #1
|
Common #1
|
||||||
|
|
||||||
|
By Another Author (3) and A U Thor (2)
|
||||||
|
via Another Committer
|
||||||
* left:
|
* left:
|
||||||
Left #5
|
Left #5
|
||||||
Left #4
|
Left #4
|
||||||
|
Reference in New Issue
Block a user