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:
Junio C Hamano 2012-04-20 15:48:33 -07:00
Родитель 0bb2ee1b7d 418a1435f1
Коммит 503c15ac09
2 изменённых файлов: 134 добавлений и 7 удалений

Просмотреть файл

@ -27,6 +27,8 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
merge_log_config = DEFAULT_MERGE_LOG_LEN;
} else if (!strcmp(key, "merge.branchdesc")) {
use_branch_desc = git_config_bool(key, value);
} else {
return git_default_config(key, value, cb);
}
return 0;
}
@ -180,6 +182,101 @@ static void add_branch_desc(struct strbuf *out, const char *name)
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,
struct origin_data *origin_data,
struct commit *head,
@ -190,6 +287,8 @@ static void shortlog(const char *name,
struct commit *commit;
struct object *branch;
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;
struct strbuf sb = STRBUF_INIT;
const unsigned char *sha1 = origin_data->sha1;
@ -199,7 +298,6 @@ static void shortlog(const char *name,
return;
setup_revisions(0, NULL, rev, NULL);
rev->ignore_merges = 1;
add_pending_object(rev, branch, name);
add_pending_object(rev, &head->object, "^HEAD");
head->object.flags |= UNINTERESTING;
@ -208,10 +306,15 @@ static void shortlog(const char *name,
while ((commit = get_revision(rev)) != NULL) {
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;
}
if (!count)
/* the 'tip' committer */
record_person('c', &committers, commit);
record_person('a', &authors, commit);
count++;
if (subjects.nr > limit)
continue;
@ -226,6 +329,7 @@ static void shortlog(const char *name,
string_list_append(&subjects, strbuf_detach(&sb, NULL));
}
add_people_info(out, &authors, &committers);
if (count > limit)
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
else
@ -246,6 +350,8 @@ static void shortlog(const char *name,
rev->commits = NULL;
rev->pending.nr = 0;
string_list_clear(&authors, 0);
string_list_clear(&committers, 0);
string_list_clear(&subjects, 0);
}

Просмотреть файл

@ -35,15 +35,18 @@ test_expect_success setup '
echo "l3" >two &&
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 &&
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 &&
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 checkout right &&
@ -99,6 +102,8 @@ test_expect_success '[merge] summary/log configuration' '
cat >expected <<-EOF &&
Merge branch ${apos}left${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left:
Left #5
Left #4
@ -144,6 +149,8 @@ test_expect_success 'merge.log=3 limits shortlog length' '
cat >expected <<-EOF &&
Merge branch ${apos}left${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left: (5 commits)
Left #5
Left #4
@ -159,6 +166,8 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
cat >expected <<-EOF &&
Merge branch ${apos}left${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left:
Left #5
Left #4
@ -181,6 +190,8 @@ test_expect_success '--log=3 limits shortlog length' '
cat >expected <<-EOF &&
Merge branch ${apos}left${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left: (5 commits)
Left #5
Left #4
@ -196,6 +207,8 @@ test_expect_success '--log=5 shows all 5 commits' '
cat >expected <<-EOF &&
Merge branch ${apos}left${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left:
Left #5
Left #4
@ -225,6 +238,8 @@ test_expect_success 'fmt-merge-msg -m' '
cat >expected.log <<-EOF &&
Sync with left
By Another Author (3) and A U Thor (2)
via Another Committer
* ${apos}left${apos} of $(pwd):
Left #5
Left #4
@ -256,6 +271,8 @@ test_expect_success 'setup: expected shortlog for two branches' '
cat >expected <<-EOF
Merge branches ${apos}left${apos} and ${apos}right${apos}
By Another Author (3) and A U Thor (2)
via Another Committer
* left:
Left #5
Left #4
@ -379,6 +396,8 @@ test_expect_success 'merge-msg two tags' '
Common #2
Common #1
By Another Author (3) and A U Thor (2)
via Another Committer
* tag ${apos}tag-l5${apos}:
Left #5
Left #4
@ -407,6 +426,8 @@ test_expect_success 'merge-msg tag and branch' '
Common #2
Common #1
By Another Author (3) and A U Thor (2)
via Another Committer
* left:
Left #5
Left #4