fmt-merge-msg.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. #include "config.h"
  2. #include "refs.h"
  3. #include "object-store.h"
  4. #include "diff.h"
  5. #include "revision.h"
  6. #include "tag.h"
  7. #include "string-list.h"
  8. #include "branch.h"
  9. #include "fmt-merge-msg.h"
  10. #include "commit-reach.h"
  11. static int use_branch_desc;
  12. static int suppress_dest_pattern_seen;
  13. static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
  14. int fmt_merge_msg_config(const char *key, const char *value, void *cb)
  15. {
  16. if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
  17. int is_bool;
  18. merge_log_config = git_config_bool_or_int(key, value, &is_bool);
  19. if (!is_bool && merge_log_config < 0)
  20. return error("%s: negative length %s", key, value);
  21. if (is_bool && merge_log_config)
  22. merge_log_config = DEFAULT_MERGE_LOG_LEN;
  23. } else if (!strcmp(key, "merge.branchdesc")) {
  24. use_branch_desc = git_config_bool(key, value);
  25. } else if (!strcmp(key, "merge.suppressdest")) {
  26. if (!value)
  27. return config_error_nonbool(key);
  28. if (!*value)
  29. string_list_clear(&suppress_dest_patterns, 0);
  30. else
  31. string_list_append(&suppress_dest_patterns, value);
  32. suppress_dest_pattern_seen = 1;
  33. } else {
  34. return git_default_config(key, value, cb);
  35. }
  36. return 0;
  37. }
  38. /* merge data per repository where the merged tips came from */
  39. struct src_data {
  40. struct string_list branch, tag, r_branch, generic;
  41. int head_status;
  42. };
  43. struct origin_data {
  44. struct object_id oid;
  45. unsigned is_local_branch:1;
  46. };
  47. static void init_src_data(struct src_data *data)
  48. {
  49. data->branch.strdup_strings = 1;
  50. data->tag.strdup_strings = 1;
  51. data->r_branch.strdup_strings = 1;
  52. data->generic.strdup_strings = 1;
  53. }
  54. static struct string_list srcs = STRING_LIST_INIT_DUP;
  55. static struct string_list origins = STRING_LIST_INIT_DUP;
  56. struct merge_parents {
  57. int alloc, nr;
  58. struct merge_parent {
  59. struct object_id given;
  60. struct object_id commit;
  61. unsigned char used;
  62. } *item;
  63. };
  64. /*
  65. * I know, I know, this is inefficient, but you won't be pulling and merging
  66. * hundreds of heads at a time anyway.
  67. */
  68. static struct merge_parent *find_merge_parent(struct merge_parents *table,
  69. struct object_id *given,
  70. struct object_id *commit)
  71. {
  72. int i;
  73. for (i = 0; i < table->nr; i++) {
  74. if (given && !oideq(&table->item[i].given, given))
  75. continue;
  76. if (commit && !oideq(&table->item[i].commit, commit))
  77. continue;
  78. return &table->item[i];
  79. }
  80. return NULL;
  81. }
  82. static void add_merge_parent(struct merge_parents *table,
  83. struct object_id *given,
  84. struct object_id *commit)
  85. {
  86. if (table->nr && find_merge_parent(table, given, commit))
  87. return;
  88. ALLOC_GROW(table->item, table->nr + 1, table->alloc);
  89. oidcpy(&table->item[table->nr].given, given);
  90. oidcpy(&table->item[table->nr].commit, commit);
  91. table->item[table->nr].used = 0;
  92. table->nr++;
  93. }
  94. static int handle_line(char *line, struct merge_parents *merge_parents)
  95. {
  96. int i, len = strlen(line);
  97. struct origin_data *origin_data;
  98. char *src;
  99. const char *origin, *tag_name;
  100. struct src_data *src_data;
  101. struct string_list_item *item;
  102. int pulling_head = 0;
  103. struct object_id oid;
  104. const unsigned hexsz = the_hash_algo->hexsz;
  105. if (len < hexsz + 3 || line[hexsz] != '\t')
  106. return 1;
  107. if (starts_with(line + hexsz + 1, "not-for-merge"))
  108. return 0;
  109. if (line[hexsz + 1] != '\t')
  110. return 2;
  111. i = get_oid_hex(line, &oid);
  112. if (i)
  113. return 3;
  114. if (!find_merge_parent(merge_parents, &oid, NULL))
  115. return 0; /* subsumed by other parents */
  116. origin_data = xcalloc(1, sizeof(struct origin_data));
  117. oidcpy(&origin_data->oid, &oid);
  118. if (line[len - 1] == '\n')
  119. line[len - 1] = 0;
  120. line += hexsz + 2;
  121. /*
  122. * At this point, line points at the beginning of comment e.g.
  123. * "branch 'frotz' of git://that/repository.git".
  124. * Find the repository name and point it with src.
  125. */
  126. src = strstr(line, " of ");
  127. if (src) {
  128. *src = 0;
  129. src += 4;
  130. pulling_head = 0;
  131. } else {
  132. src = line;
  133. pulling_head = 1;
  134. }
  135. item = unsorted_string_list_lookup(&srcs, src);
  136. if (!item) {
  137. item = string_list_append(&srcs, src);
  138. item->util = xcalloc(1, sizeof(struct src_data));
  139. init_src_data(item->util);
  140. }
  141. src_data = item->util;
  142. if (pulling_head) {
  143. origin = src;
  144. src_data->head_status |= 1;
  145. } else if (skip_prefix(line, "branch ", &origin)) {
  146. origin_data->is_local_branch = 1;
  147. string_list_append(&src_data->branch, origin);
  148. src_data->head_status |= 2;
  149. } else if (skip_prefix(line, "tag ", &tag_name)) {
  150. origin = line;
  151. string_list_append(&src_data->tag, tag_name);
  152. src_data->head_status |= 2;
  153. } else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
  154. string_list_append(&src_data->r_branch, origin);
  155. src_data->head_status |= 2;
  156. } else {
  157. origin = src;
  158. string_list_append(&src_data->generic, line);
  159. src_data->head_status |= 2;
  160. }
  161. if (!strcmp(".", src) || !strcmp(src, origin)) {
  162. int len = strlen(origin);
  163. if (origin[0] == '\'' && origin[len - 1] == '\'')
  164. origin = xmemdupz(origin + 1, len - 2);
  165. } else
  166. origin = xstrfmt("%s of %s", origin, src);
  167. if (strcmp(".", src))
  168. origin_data->is_local_branch = 0;
  169. string_list_append(&origins, origin)->util = origin_data;
  170. return 0;
  171. }
  172. static void print_joined(const char *singular, const char *plural,
  173. struct string_list *list, struct strbuf *out)
  174. {
  175. if (list->nr == 0)
  176. return;
  177. if (list->nr == 1) {
  178. strbuf_addf(out, "%s%s", singular, list->items[0].string);
  179. } else {
  180. int i;
  181. strbuf_addstr(out, plural);
  182. for (i = 0; i < list->nr - 1; i++)
  183. strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
  184. list->items[i].string);
  185. strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
  186. }
  187. }
  188. static void add_branch_desc(struct strbuf *out, const char *name)
  189. {
  190. struct strbuf desc = STRBUF_INIT;
  191. if (!read_branch_desc(&desc, name)) {
  192. const char *bp = desc.buf;
  193. while (*bp) {
  194. const char *ep = strchrnul(bp, '\n');
  195. if (*ep)
  196. ep++;
  197. strbuf_addf(out, " : %.*s", (int)(ep - bp), bp);
  198. bp = ep;
  199. }
  200. strbuf_complete_line(out);
  201. }
  202. strbuf_release(&desc);
  203. }
  204. #define util_as_integral(elem) ((intptr_t)((elem)->util))
  205. static void record_person_from_buf(int which, struct string_list *people,
  206. const char *buffer)
  207. {
  208. char *name_buf, *name, *name_end;
  209. struct string_list_item *elem;
  210. const char *field;
  211. field = (which == 'a') ? "\nauthor " : "\ncommitter ";
  212. name = strstr(buffer, field);
  213. if (!name)
  214. return;
  215. name += strlen(field);
  216. name_end = strchrnul(name, '<');
  217. if (*name_end)
  218. name_end--;
  219. while (isspace(*name_end) && name <= name_end)
  220. name_end--;
  221. if (name_end < name)
  222. return;
  223. name_buf = xmemdupz(name, name_end - name + 1);
  224. elem = string_list_lookup(people, name_buf);
  225. if (!elem) {
  226. elem = string_list_insert(people, name_buf);
  227. elem->util = (void *)0;
  228. }
  229. elem->util = (void*)(util_as_integral(elem) + 1);
  230. free(name_buf);
  231. }
  232. static void record_person(int which, struct string_list *people,
  233. struct commit *commit)
  234. {
  235. const char *buffer = get_commit_buffer(commit, NULL);
  236. record_person_from_buf(which, people, buffer);
  237. unuse_commit_buffer(commit, buffer);
  238. }
  239. static int cmp_string_list_util_as_integral(const void *a_, const void *b_)
  240. {
  241. const struct string_list_item *a = a_, *b = b_;
  242. return util_as_integral(b) - util_as_integral(a);
  243. }
  244. static void add_people_count(struct strbuf *out, struct string_list *people)
  245. {
  246. if (people->nr == 1)
  247. strbuf_addstr(out, people->items[0].string);
  248. else if (people->nr == 2)
  249. strbuf_addf(out, "%s (%d) and %s (%d)",
  250. people->items[0].string,
  251. (int)util_as_integral(&people->items[0]),
  252. people->items[1].string,
  253. (int)util_as_integral(&people->items[1]));
  254. else if (people->nr)
  255. strbuf_addf(out, "%s (%d) and others",
  256. people->items[0].string,
  257. (int)util_as_integral(&people->items[0]));
  258. }
  259. static void credit_people(struct strbuf *out,
  260. struct string_list *them,
  261. int kind)
  262. {
  263. const char *label;
  264. const char *me;
  265. if (kind == 'a') {
  266. label = "By";
  267. me = git_author_info(IDENT_NO_DATE);
  268. } else {
  269. label = "Via";
  270. me = git_committer_info(IDENT_NO_DATE);
  271. }
  272. if (!them->nr ||
  273. (them->nr == 1 &&
  274. me &&
  275. skip_prefix(me, them->items->string, &me) &&
  276. starts_with(me, " <")))
  277. return;
  278. strbuf_addf(out, "\n%c %s ", comment_line_char, label);
  279. add_people_count(out, them);
  280. }
  281. static void add_people_info(struct strbuf *out,
  282. struct string_list *authors,
  283. struct string_list *committers)
  284. {
  285. QSORT(authors->items, authors->nr,
  286. cmp_string_list_util_as_integral);
  287. QSORT(committers->items, committers->nr,
  288. cmp_string_list_util_as_integral);
  289. credit_people(out, authors, 'a');
  290. credit_people(out, committers, 'c');
  291. }
  292. static void shortlog(const char *name,
  293. struct origin_data *origin_data,
  294. struct commit *head,
  295. struct rev_info *rev,
  296. struct fmt_merge_msg_opts *opts,
  297. struct strbuf *out)
  298. {
  299. int i, count = 0;
  300. struct commit *commit;
  301. struct object *branch;
  302. struct string_list subjects = STRING_LIST_INIT_DUP;
  303. struct string_list authors = STRING_LIST_INIT_DUP;
  304. struct string_list committers = STRING_LIST_INIT_DUP;
  305. int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
  306. struct strbuf sb = STRBUF_INIT;
  307. const struct object_id *oid = &origin_data->oid;
  308. int limit = opts->shortlog_len;
  309. branch = deref_tag(the_repository, parse_object(the_repository, oid),
  310. oid_to_hex(oid),
  311. the_hash_algo->hexsz);
  312. if (!branch || branch->type != OBJ_COMMIT)
  313. return;
  314. setup_revisions(0, NULL, rev, NULL);
  315. add_pending_object(rev, branch, name);
  316. add_pending_object(rev, &head->object, "^HEAD");
  317. head->object.flags |= UNINTERESTING;
  318. if (prepare_revision_walk(rev))
  319. die("revision walk setup failed");
  320. while ((commit = get_revision(rev)) != NULL) {
  321. struct pretty_print_context ctx = {0};
  322. if (commit->parents && commit->parents->next) {
  323. /* do not list a merge but count committer */
  324. if (opts->credit_people)
  325. record_person('c', &committers, commit);
  326. continue;
  327. }
  328. if (!count && opts->credit_people)
  329. /* the 'tip' committer */
  330. record_person('c', &committers, commit);
  331. if (opts->credit_people)
  332. record_person('a', &authors, commit);
  333. count++;
  334. if (subjects.nr > limit)
  335. continue;
  336. format_commit_message(commit, "%s", &sb, &ctx);
  337. strbuf_ltrim(&sb);
  338. if (!sb.len)
  339. string_list_append(&subjects,
  340. oid_to_hex(&commit->object.oid));
  341. else
  342. string_list_append_nodup(&subjects,
  343. strbuf_detach(&sb, NULL));
  344. }
  345. if (opts->credit_people)
  346. add_people_info(out, &authors, &committers);
  347. if (count > limit)
  348. strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
  349. else
  350. strbuf_addf(out, "\n* %s:\n", name);
  351. if (origin_data->is_local_branch && use_branch_desc)
  352. add_branch_desc(out, name);
  353. for (i = 0; i < subjects.nr; i++)
  354. if (i >= limit)
  355. strbuf_addstr(out, " ...\n");
  356. else
  357. strbuf_addf(out, " %s\n", subjects.items[i].string);
  358. clear_commit_marks((struct commit *)branch, flags);
  359. clear_commit_marks(head, flags);
  360. free_commit_list(rev->commits);
  361. rev->commits = NULL;
  362. rev->pending.nr = 0;
  363. string_list_clear(&authors, 0);
  364. string_list_clear(&committers, 0);
  365. string_list_clear(&subjects, 0);
  366. }
  367. /*
  368. * See if dest_branch matches with any glob pattern on the
  369. * suppress_dest_patterns list.
  370. *
  371. * We may want to also allow negative matches e.g. ":!glob" like we do
  372. * for pathspec, but for now, let's keep it simple and stupid.
  373. */
  374. static int dest_suppressed(const char *dest_branch)
  375. {
  376. struct string_list_item *item;
  377. for_each_string_list_item(item, &suppress_dest_patterns) {
  378. if (!wildmatch(item->string, dest_branch, WM_PATHNAME))
  379. return 1;
  380. }
  381. return 0;
  382. }
  383. static void fmt_merge_msg_title(struct strbuf *out,
  384. const char *current_branch)
  385. {
  386. int i = 0;
  387. char *sep = "";
  388. strbuf_addstr(out, "Merge ");
  389. for (i = 0; i < srcs.nr; i++) {
  390. struct src_data *src_data = srcs.items[i].util;
  391. const char *subsep = "";
  392. strbuf_addstr(out, sep);
  393. sep = "; ";
  394. if (src_data->head_status == 1) {
  395. strbuf_addstr(out, srcs.items[i].string);
  396. continue;
  397. }
  398. if (src_data->head_status == 3) {
  399. subsep = ", ";
  400. strbuf_addstr(out, "HEAD");
  401. }
  402. if (src_data->branch.nr) {
  403. strbuf_addstr(out, subsep);
  404. subsep = ", ";
  405. print_joined("branch ", "branches ", &src_data->branch,
  406. out);
  407. }
  408. if (src_data->r_branch.nr) {
  409. strbuf_addstr(out, subsep);
  410. subsep = ", ";
  411. print_joined("remote-tracking branch ", "remote-tracking branches ",
  412. &src_data->r_branch, out);
  413. }
  414. if (src_data->tag.nr) {
  415. strbuf_addstr(out, subsep);
  416. subsep = ", ";
  417. print_joined("tag ", "tags ", &src_data->tag, out);
  418. }
  419. if (src_data->generic.nr) {
  420. strbuf_addstr(out, subsep);
  421. print_joined("commit ", "commits ", &src_data->generic,
  422. out);
  423. }
  424. if (strcmp(".", srcs.items[i].string))
  425. strbuf_addf(out, " of %s", srcs.items[i].string);
  426. }
  427. if (!dest_suppressed(current_branch))
  428. strbuf_addf(out, " into %s", current_branch);
  429. strbuf_addch(out, '\n');
  430. }
  431. static void fmt_tag_signature(struct strbuf *tagbuf,
  432. struct strbuf *sig,
  433. const char *buf,
  434. unsigned long len)
  435. {
  436. const char *tag_body = strstr(buf, "\n\n");
  437. if (tag_body) {
  438. tag_body += 2;
  439. strbuf_add(tagbuf, tag_body, buf + len - tag_body);
  440. }
  441. strbuf_complete_line(tagbuf);
  442. if (sig->len) {
  443. strbuf_addch(tagbuf, '\n');
  444. strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
  445. }
  446. }
  447. static void fmt_merge_msg_sigs(struct strbuf *out)
  448. {
  449. int i, tag_number = 0, first_tag = 0;
  450. struct strbuf tagbuf = STRBUF_INIT;
  451. for (i = 0; i < origins.nr; i++) {
  452. struct object_id *oid = origins.items[i].util;
  453. enum object_type type;
  454. unsigned long size, len;
  455. char *buf = read_object_file(oid, &type, &size);
  456. struct signature_check sigc = { NULL };
  457. struct strbuf sig = STRBUF_INIT;
  458. if (!buf || type != OBJ_TAG)
  459. goto next;
  460. len = parse_signature(buf, size);
  461. if (size == len)
  462. ; /* merely annotated */
  463. else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
  464. !sigc.gpg_output)
  465. strbuf_addstr(&sig, "gpg verification failed.\n");
  466. else
  467. strbuf_addstr(&sig, sigc.gpg_output);
  468. signature_check_clear(&sigc);
  469. if (!tag_number++) {
  470. fmt_tag_signature(&tagbuf, &sig, buf, len);
  471. first_tag = i;
  472. } else {
  473. if (tag_number == 2) {
  474. struct strbuf tagline = STRBUF_INIT;
  475. strbuf_addch(&tagline, '\n');
  476. strbuf_add_commented_lines(&tagline,
  477. origins.items[first_tag].string,
  478. strlen(origins.items[first_tag].string));
  479. strbuf_insert(&tagbuf, 0, tagline.buf,
  480. tagline.len);
  481. strbuf_release(&tagline);
  482. }
  483. strbuf_addch(&tagbuf, '\n');
  484. strbuf_add_commented_lines(&tagbuf,
  485. origins.items[i].string,
  486. strlen(origins.items[i].string));
  487. fmt_tag_signature(&tagbuf, &sig, buf, len);
  488. }
  489. strbuf_release(&sig);
  490. next:
  491. free(buf);
  492. }
  493. if (tagbuf.len) {
  494. strbuf_addch(out, '\n');
  495. strbuf_addbuf(out, &tagbuf);
  496. }
  497. strbuf_release(&tagbuf);
  498. }
  499. static void find_merge_parents(struct merge_parents *result,
  500. struct strbuf *in, struct object_id *head)
  501. {
  502. struct commit_list *parents;
  503. struct commit *head_commit;
  504. int pos = 0, i, j;
  505. parents = NULL;
  506. while (pos < in->len) {
  507. int len;
  508. char *p = in->buf + pos;
  509. char *newline = strchr(p, '\n');
  510. const char *q;
  511. struct object_id oid;
  512. struct commit *parent;
  513. struct object *obj;
  514. len = newline ? newline - p : strlen(p);
  515. pos += len + !!newline;
  516. if (parse_oid_hex(p, &oid, &q) ||
  517. q[0] != '\t' ||
  518. q[1] != '\t')
  519. continue; /* skip not-for-merge */
  520. /*
  521. * Do not use get_merge_parent() here; we do not have
  522. * "name" here and we do not want to contaminate its
  523. * util field yet.
  524. */
  525. obj = parse_object(the_repository, &oid);
  526. parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
  527. if (!parent)
  528. continue;
  529. commit_list_insert(parent, &parents);
  530. add_merge_parent(result, &obj->oid, &parent->object.oid);
  531. }
  532. head_commit = lookup_commit(the_repository, head);
  533. if (head_commit)
  534. commit_list_insert(head_commit, &parents);
  535. reduce_heads_replace(&parents);
  536. while (parents) {
  537. struct commit *cmit = pop_commit(&parents);
  538. for (i = 0; i < result->nr; i++)
  539. if (oideq(&result->item[i].commit, &cmit->object.oid))
  540. result->item[i].used = 1;
  541. }
  542. for (i = j = 0; i < result->nr; i++) {
  543. if (result->item[i].used) {
  544. if (i != j)
  545. result->item[j] = result->item[i];
  546. j++;
  547. }
  548. }
  549. result->nr = j;
  550. }
  551. int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
  552. struct fmt_merge_msg_opts *opts)
  553. {
  554. int i = 0, pos = 0;
  555. struct object_id head_oid;
  556. const char *current_branch;
  557. void *current_branch_to_free;
  558. struct merge_parents merge_parents;
  559. if (!suppress_dest_pattern_seen)
  560. string_list_append(&suppress_dest_patterns, "master");
  561. memset(&merge_parents, 0, sizeof(merge_parents));
  562. /* get current branch */
  563. current_branch = current_branch_to_free =
  564. resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
  565. if (!current_branch)
  566. die("No current branch");
  567. if (starts_with(current_branch, "refs/heads/"))
  568. current_branch += 11;
  569. find_merge_parents(&merge_parents, in, &head_oid);
  570. /* get a line */
  571. while (pos < in->len) {
  572. int len;
  573. char *newline, *p = in->buf + pos;
  574. newline = strchr(p, '\n');
  575. len = newline ? newline - p : strlen(p);
  576. pos += len + !!newline;
  577. i++;
  578. p[len] = 0;
  579. if (handle_line(p, &merge_parents))
  580. die("error in line %d: %.*s", i, len, p);
  581. }
  582. if (opts->add_title && srcs.nr)
  583. fmt_merge_msg_title(out, current_branch);
  584. if (origins.nr)
  585. fmt_merge_msg_sigs(out);
  586. if (opts->shortlog_len) {
  587. struct commit *head;
  588. struct rev_info rev;
  589. head = lookup_commit_or_die(&head_oid, "HEAD");
  590. repo_init_revisions(the_repository, &rev, NULL);
  591. rev.commit_format = CMIT_FMT_ONELINE;
  592. rev.ignore_merges = 1;
  593. rev.limited = 1;
  594. strbuf_complete_line(out);
  595. for (i = 0; i < origins.nr; i++)
  596. shortlog(origins.items[i].string,
  597. origins.items[i].util,
  598. head, &rev, opts, out);
  599. }
  600. strbuf_complete_line(out);
  601. free(current_branch_to_free);
  602. free(merge_parents.item);
  603. return 0;
  604. }