27
merge_log_config = DEFAULT_MERGE_LOG_LEN;
28
} else if (!strcmp(key, "merge.branchdesc")) {
29
use_branch_desc = git_config_bool(key, value);
30
+ } else {
31
+ return git_default_config(key, value, cb);
32
}
33
return 0;
34
}
182
strbuf_release(&desc);
183
}
184
185
+#define util_as_integral(elem) ((intptr_t)((elem)->util))
186
+
187
+static void record_person(int which, struct string_list *people,
188
+ struct commit *commit)
189
+{
190
+ char name_buf[MAX_GITNAME], *name, *name_end;
191
+ struct string_list_item *elem;
192
+ const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
193
+
194
+ name = strstr(commit->buffer, field);
195
+ if (!name)
196
+ return;
197
+ name += strlen(field);
198
+ name_end = strchrnul(name, '<');
199
+ if (*name_end)
200
+ name_end--;
201
+ while (isspace(*name_end) && name <= name_end)
202
+ name_end--;
203
+ if (name_end < name || name + MAX_GITNAME <= name_end)
204
+ return;
205
+ memcpy(name_buf, name, name_end - name + 1);
206
+ name_buf[name_end - name + 1] = '\0';
207
+
208
+ elem = string_list_lookup(people, name_buf);
209
+ if (!elem) {
210
+ elem = string_list_insert(people, name_buf);
211
+ elem->util = (void *)0;
212
+ }
213
+ elem->util = (void*)(util_as_integral(elem) + 1);
214
+}
215
+
216
+static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
217
+{
218
+ const struct string_list_item *a = a_, *b = b_;
219
+ return util_as_integral(b) - util_as_integral(a);
220
+}
221
+
222
+static void add_people_count(struct strbuf *out, struct string_list *people)
223
+{
224
+ if (people->nr == 1)
225
+ strbuf_addf(out, "%s", people->items[0].string);
226
+ else if (people->nr == 2)
227
+ strbuf_addf(out, "%s (%d) and %s (%d)",
228
+ people->items[0].string,
229
+ (int)util_as_integral(&people->items[0]),
230
+ people->items[1].string,
231
+ (int)util_as_integral(&people->items[1]));
232
+ else if (people->nr)
233
+ strbuf_addf(out, "%s (%d) and others",
234
+ people->items[0].string,
235
+ (int)util_as_integral(&people->items[0]));
236
+}
237
+
238
+static void credit_people(struct strbuf *out,
239
+ struct string_list *them,
240
+ int kind)
241
+{
242
+ const char *label;
243
+ const char *me;
244
+
245
+ if (kind == 'a') {
246
+ label = "\nBy ";
247
+ me = git_author_info(IDENT_NO_DATE);
248
+ } else {
249
+ label = "\nvia ";
250
+ me = git_committer_info(IDENT_NO_DATE);
251
+ }
252
+
253
+ if (!them->nr ||
254
+ (them->nr == 1 &&
255
+ me &&
256
+ (me = skip_prefix(me, them->items->string)) != NULL &&
257
+ skip_prefix(me, " <")))
258
+ return;
259
+ strbuf_addstr(out, label);
260
+ add_people_count(out, them);
261
+}
262
+
263
+static void add_people_info(struct strbuf *out,
264
+ struct string_list *authors,
265
+ struct string_list *committers)
266
+{
267
+ if (authors->nr)
268
+ qsort(authors->items,
269
+ authors->nr, sizeof(authors->items[0]),
270
+ cmp_string_list_util_as_integral);
271
+ if (committers->nr)
272
+ qsort(committers->items,
273
+ committers->nr, sizeof(committers->items[0]),
274
+ cmp_string_list_util_as_integral);
275
+
276
+ credit_people(out, authors, 'a');
277
+ credit_people(out, committers, 'c');
278
+}
279
+
280
static void shortlog(const char *name,
281
struct origin_data *origin_data,
282
struct commit *head,
287
struct commit *commit;
288
struct object *branch;
289
struct string_list subjects = STRING_LIST_INIT_DUP;
290
+ struct string_list authors = STRING_LIST_INIT_DUP;
291
+ struct string_list committers = STRING_LIST_INIT_DUP;
292
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
293
struct strbuf sb = STRBUF_INIT;
294
const unsigned char *sha1 = origin_data->sha1;
298
return;
299
300
setup_revisions(0, NULL, rev, NULL);
202
- rev->ignore_merges = 1;
301
add_pending_object(rev, branch, name);
302
add_pending_object(rev, &head->object, "^HEAD");
303
head->object.flags |= UNINTERESTING;
306
while ((commit = get_revision(rev)) != NULL) {
307
struct pretty_print_context ctx = {0};
308
211
- /* ignore merges */
212
- if (commit->parents && commit->parents->next)
309
+ if (commit->parents && commit->parents->next) {
310
+ /* do not list a merge but count committer */
311
+ record_person('c', &committers, commit);
312
continue;
214
-
313
+ }
314
+ if (!count)
315
+ /* the 'tip' committer */
316
+ record_person('c', &committers, commit);
317
+ record_person('a', &authors, commit);
318
count++;
319
if (subjects.nr > limit)
320
continue;
329
string_list_append(&subjects, strbuf_detach(&sb, NULL));
330
}
331
332
+ add_people_info(out, &authors, &committers);
333
if (count > limit)
334
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
335
else
350
rev->commits = NULL;
351
rev->pending.nr = 0;
352
353
+ string_list_clear(&authors, 0);
354
+ string_list_clear(&committers, 0);
355
string_list_clear(&subjects, 0);
356
}
357