log-tree.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. #include "cache.h"
  2. #include "config.h"
  3. #include "diff.h"
  4. #include "object-store.h"
  5. #include "repository.h"
  6. #include "commit.h"
  7. #include "tag.h"
  8. #include "graph.h"
  9. #include "log-tree.h"
  10. #include "reflog-walk.h"
  11. #include "refs.h"
  12. #include "string-list.h"
  13. #include "color.h"
  14. #include "gpg-interface.h"
  15. #include "sequencer.h"
  16. #include "line-log.h"
  17. #include "help.h"
  18. #include "range-diff.h"
  19. static struct decoration name_decoration = { "object names" };
  20. static int decoration_loaded;
  21. static int decoration_flags;
  22. static char decoration_colors[][COLOR_MAXLEN] = {
  23. GIT_COLOR_RESET,
  24. GIT_COLOR_BOLD_GREEN, /* REF_LOCAL */
  25. GIT_COLOR_BOLD_RED, /* REF_REMOTE */
  26. GIT_COLOR_BOLD_YELLOW, /* REF_TAG */
  27. GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
  28. GIT_COLOR_BOLD_CYAN, /* REF_HEAD */
  29. GIT_COLOR_BOLD_BLUE, /* GRAFTED */
  30. };
  31. static const char *color_decorate_slots[] = {
  32. [DECORATION_REF_LOCAL] = "branch",
  33. [DECORATION_REF_REMOTE] = "remoteBranch",
  34. [DECORATION_REF_TAG] = "tag",
  35. [DECORATION_REF_STASH] = "stash",
  36. [DECORATION_REF_HEAD] = "HEAD",
  37. [DECORATION_GRAFTED] = "grafted",
  38. };
  39. static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
  40. {
  41. if (want_color(decorate_use_color))
  42. return decoration_colors[ix];
  43. return "";
  44. }
  45. define_list_config_array(color_decorate_slots);
  46. int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
  47. {
  48. int slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);
  49. if (slot < 0)
  50. return 0;
  51. if (!value)
  52. return config_error_nonbool(var);
  53. return color_parse(value, decoration_colors[slot]);
  54. }
  55. /*
  56. * log-tree.c uses DIFF_OPT_TST for determining whether to use color
  57. * for showing the commit sha1, use the same check for --decorate
  58. */
  59. #define decorate_get_color_opt(o, ix) \
  60. decorate_get_color((o)->use_color, ix)
  61. void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
  62. {
  63. struct name_decoration *res;
  64. FLEX_ALLOC_STR(res, name, name);
  65. res->type = type;
  66. res->next = add_decoration(&name_decoration, obj, res);
  67. }
  68. const struct name_decoration *get_name_decoration(const struct object *obj)
  69. {
  70. load_ref_decorations(NULL, DECORATE_SHORT_REFS);
  71. return lookup_decoration(&name_decoration, obj);
  72. }
  73. static int match_ref_pattern(const char *refname,
  74. const struct string_list_item *item)
  75. {
  76. int matched = 0;
  77. if (item->util == NULL) {
  78. if (!wildmatch(item->string, refname, 0))
  79. matched = 1;
  80. } else {
  81. const char *rest;
  82. if (skip_prefix(refname, item->string, &rest) &&
  83. (!*rest || *rest == '/'))
  84. matched = 1;
  85. }
  86. return matched;
  87. }
  88. static int ref_filter_match(const char *refname,
  89. const struct decoration_filter *filter)
  90. {
  91. struct string_list_item *item;
  92. const struct string_list *exclude_patterns = filter->exclude_ref_pattern;
  93. const struct string_list *include_patterns = filter->include_ref_pattern;
  94. const struct string_list *exclude_patterns_config =
  95. filter->exclude_ref_config_pattern;
  96. if (exclude_patterns && exclude_patterns->nr) {
  97. for_each_string_list_item(item, exclude_patterns) {
  98. if (match_ref_pattern(refname, item))
  99. return 0;
  100. }
  101. }
  102. if (include_patterns && include_patterns->nr) {
  103. for_each_string_list_item(item, include_patterns) {
  104. if (match_ref_pattern(refname, item))
  105. return 1;
  106. }
  107. return 0;
  108. }
  109. if (exclude_patterns_config && exclude_patterns_config->nr) {
  110. for_each_string_list_item(item, exclude_patterns_config) {
  111. if (match_ref_pattern(refname, item))
  112. return 0;
  113. }
  114. }
  115. return 1;
  116. }
  117. static int add_ref_decoration(const char *refname, const struct object_id *oid,
  118. int flags, void *cb_data)
  119. {
  120. struct object *obj;
  121. enum decoration_type type = DECORATION_NONE;
  122. struct decoration_filter *filter = (struct decoration_filter *)cb_data;
  123. if (filter && !ref_filter_match(refname, filter))
  124. return 0;
  125. if (starts_with(refname, git_replace_ref_base)) {
  126. struct object_id original_oid;
  127. if (!read_replace_refs)
  128. return 0;
  129. if (get_oid_hex(refname + strlen(git_replace_ref_base),
  130. &original_oid)) {
  131. warning("invalid replace ref %s", refname);
  132. return 0;
  133. }
  134. obj = parse_object(the_repository, &original_oid);
  135. if (obj)
  136. add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
  137. return 0;
  138. }
  139. obj = parse_object(the_repository, oid);
  140. if (!obj)
  141. return 0;
  142. if (starts_with(refname, "refs/heads/"))
  143. type = DECORATION_REF_LOCAL;
  144. else if (starts_with(refname, "refs/remotes/"))
  145. type = DECORATION_REF_REMOTE;
  146. else if (starts_with(refname, "refs/tags/"))
  147. type = DECORATION_REF_TAG;
  148. else if (!strcmp(refname, "refs/stash"))
  149. type = DECORATION_REF_STASH;
  150. else if (!strcmp(refname, "HEAD"))
  151. type = DECORATION_REF_HEAD;
  152. add_name_decoration(type, refname, obj);
  153. while (obj->type == OBJ_TAG) {
  154. obj = ((struct tag *)obj)->tagged;
  155. if (!obj)
  156. break;
  157. if (!obj->parsed)
  158. parse_object(the_repository, &obj->oid);
  159. add_name_decoration(DECORATION_REF_TAG, refname, obj);
  160. }
  161. return 0;
  162. }
  163. static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
  164. {
  165. struct commit *commit = lookup_commit(the_repository, &graft->oid);
  166. if (!commit)
  167. return 0;
  168. add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
  169. return 0;
  170. }
  171. void load_ref_decorations(struct decoration_filter *filter, int flags)
  172. {
  173. if (!decoration_loaded) {
  174. if (filter) {
  175. struct string_list_item *item;
  176. for_each_string_list_item(item, filter->exclude_ref_pattern) {
  177. normalize_glob_ref(item, NULL, item->string);
  178. }
  179. for_each_string_list_item(item, filter->include_ref_pattern) {
  180. normalize_glob_ref(item, NULL, item->string);
  181. }
  182. for_each_string_list_item(item, filter->exclude_ref_config_pattern) {
  183. normalize_glob_ref(item, NULL, item->string);
  184. }
  185. }
  186. decoration_loaded = 1;
  187. decoration_flags = flags;
  188. for_each_ref(add_ref_decoration, filter);
  189. head_ref(add_ref_decoration, filter);
  190. for_each_commit_graft(add_graft_decoration, filter);
  191. }
  192. }
  193. static void show_parents(struct commit *commit, int abbrev, FILE *file)
  194. {
  195. struct commit_list *p;
  196. for (p = commit->parents; p ; p = p->next) {
  197. struct commit *parent = p->item;
  198. fprintf(file, " %s", find_unique_abbrev(&parent->object.oid, abbrev));
  199. }
  200. }
  201. static void show_children(struct rev_info *opt, struct commit *commit, int abbrev)
  202. {
  203. struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
  204. for ( ; p; p = p->next) {
  205. fprintf(opt->diffopt.file, " %s", find_unique_abbrev(&p->item->object.oid, abbrev));
  206. }
  207. }
  208. /*
  209. * Do we have HEAD in the output, and also the branch it points at?
  210. * If so, find that decoration entry for that current branch.
  211. */
  212. static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
  213. {
  214. const struct name_decoration *list, *head = NULL;
  215. const char *branch_name = NULL;
  216. int rru_flags;
  217. /* First find HEAD */
  218. for (list = decoration; list; list = list->next)
  219. if (list->type == DECORATION_REF_HEAD) {
  220. head = list;
  221. break;
  222. }
  223. if (!head)
  224. return NULL;
  225. /* Now resolve and find the matching current branch */
  226. branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags);
  227. if (!branch_name || !(rru_flags & REF_ISSYMREF))
  228. return NULL;
  229. if (!starts_with(branch_name, "refs/"))
  230. return NULL;
  231. /* OK, do we have that ref in the list? */
  232. for (list = decoration; list; list = list->next)
  233. if ((list->type == DECORATION_REF_LOCAL) &&
  234. !strcmp(branch_name, list->name)) {
  235. return list;
  236. }
  237. return NULL;
  238. }
  239. static void show_name(struct strbuf *sb, const struct name_decoration *decoration)
  240. {
  241. if (decoration_flags == DECORATE_SHORT_REFS)
  242. strbuf_addstr(sb, prettify_refname(decoration->name));
  243. else
  244. strbuf_addstr(sb, decoration->name);
  245. }
  246. /*
  247. * The caller makes sure there is no funny color before calling.
  248. * format_decorations_extended makes sure the same after return.
  249. */
  250. void format_decorations_extended(struct strbuf *sb,
  251. const struct commit *commit,
  252. int use_color,
  253. const char *prefix,
  254. const char *separator,
  255. const char *suffix)
  256. {
  257. const struct name_decoration *decoration;
  258. const struct name_decoration *current_and_HEAD;
  259. const char *color_commit =
  260. diff_get_color(use_color, DIFF_COMMIT);
  261. const char *color_reset =
  262. decorate_get_color(use_color, DECORATION_NONE);
  263. decoration = get_name_decoration(&commit->object);
  264. if (!decoration)
  265. return;
  266. current_and_HEAD = current_pointed_by_HEAD(decoration);
  267. while (decoration) {
  268. /*
  269. * When both current and HEAD are there, only
  270. * show HEAD->current where HEAD would have
  271. * appeared, skipping the entry for current.
  272. */
  273. if (decoration != current_and_HEAD) {
  274. strbuf_addstr(sb, color_commit);
  275. strbuf_addstr(sb, prefix);
  276. strbuf_addstr(sb, color_reset);
  277. strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
  278. if (decoration->type == DECORATION_REF_TAG)
  279. strbuf_addstr(sb, "tag: ");
  280. show_name(sb, decoration);
  281. if (current_and_HEAD &&
  282. decoration->type == DECORATION_REF_HEAD) {
  283. strbuf_addstr(sb, " -> ");
  284. strbuf_addstr(sb, color_reset);
  285. strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
  286. show_name(sb, current_and_HEAD);
  287. }
  288. strbuf_addstr(sb, color_reset);
  289. prefix = separator;
  290. }
  291. decoration = decoration->next;
  292. }
  293. strbuf_addstr(sb, color_commit);
  294. strbuf_addstr(sb, suffix);
  295. strbuf_addstr(sb, color_reset);
  296. }
  297. void show_decorations(struct rev_info *opt, struct commit *commit)
  298. {
  299. struct strbuf sb = STRBUF_INIT;
  300. if (opt->sources) {
  301. char **slot = revision_sources_peek(opt->sources, commit);
  302. if (slot && *slot)
  303. fprintf(opt->diffopt.file, "\t%s", *slot);
  304. }
  305. if (!opt->show_decorations)
  306. return;
  307. format_decorations(&sb, commit, opt->diffopt.use_color);
  308. fputs(sb.buf, opt->diffopt.file);
  309. strbuf_release(&sb);
  310. }
  311. static unsigned int digits_in_number(unsigned int number)
  312. {
  313. unsigned int i = 10, result = 1;
  314. while (i <= number) {
  315. i *= 10;
  316. result++;
  317. }
  318. return result;
  319. }
  320. void fmt_output_subject(struct strbuf *filename,
  321. const char *subject,
  322. struct rev_info *info)
  323. {
  324. const char *suffix = info->patch_suffix;
  325. int nr = info->nr;
  326. int start_len = filename->len;
  327. int max_len = start_len + FORMAT_PATCH_NAME_MAX - (strlen(suffix) + 1);
  328. if (0 < info->reroll_count)
  329. strbuf_addf(filename, "v%d-", info->reroll_count);
  330. strbuf_addf(filename, "%04d-%s", nr, subject);
  331. if (max_len < filename->len)
  332. strbuf_setlen(filename, max_len);
  333. strbuf_addstr(filename, suffix);
  334. }
  335. void fmt_output_commit(struct strbuf *filename,
  336. struct commit *commit,
  337. struct rev_info *info)
  338. {
  339. struct pretty_print_context ctx = {0};
  340. struct strbuf subject = STRBUF_INIT;
  341. format_commit_message(commit, "%f", &subject, &ctx);
  342. fmt_output_subject(filename, subject.buf, info);
  343. strbuf_release(&subject);
  344. }
  345. void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt)
  346. {
  347. if (opt->total > 0) {
  348. strbuf_addf(sb, "Subject: [%s%s%0*d/%d] ",
  349. opt->subject_prefix,
  350. *opt->subject_prefix ? " " : "",
  351. digits_in_number(opt->total),
  352. opt->nr, opt->total);
  353. } else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) {
  354. strbuf_addf(sb, "Subject: [%s] ",
  355. opt->subject_prefix);
  356. } else {
  357. strbuf_addstr(sb, "Subject: ");
  358. }
  359. }
  360. void log_write_email_headers(struct rev_info *opt, struct commit *commit,
  361. const char **extra_headers_p,
  362. int *need_8bit_cte_p,
  363. int maybe_multipart)
  364. {
  365. const char *extra_headers = opt->extra_headers;
  366. const char *name = oid_to_hex(opt->zero_commit ?
  367. &null_oid : &commit->object.oid);
  368. *need_8bit_cte_p = 0; /* unknown */
  369. fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
  370. graph_show_oneline(opt->graph);
  371. if (opt->message_id) {
  372. fprintf(opt->diffopt.file, "Message-Id: <%s>\n", opt->message_id);
  373. graph_show_oneline(opt->graph);
  374. }
  375. if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
  376. int i, n;
  377. n = opt->ref_message_ids->nr;
  378. fprintf(opt->diffopt.file, "In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
  379. for (i = 0; i < n; i++)
  380. fprintf(opt->diffopt.file, "%s<%s>\n", (i > 0 ? "\t" : "References: "),
  381. opt->ref_message_ids->items[i].string);
  382. graph_show_oneline(opt->graph);
  383. }
  384. if (opt->mime_boundary && maybe_multipart) {
  385. static struct strbuf subject_buffer = STRBUF_INIT;
  386. static struct strbuf buffer = STRBUF_INIT;
  387. struct strbuf filename = STRBUF_INIT;
  388. *need_8bit_cte_p = -1; /* NEVER */
  389. strbuf_reset(&subject_buffer);
  390. strbuf_reset(&buffer);
  391. strbuf_addf(&subject_buffer,
  392. "%s"
  393. "MIME-Version: 1.0\n"
  394. "Content-Type: multipart/mixed;"
  395. " boundary=\"%s%s\"\n"
  396. "\n"
  397. "This is a multi-part message in MIME "
  398. "format.\n"
  399. "--%s%s\n"
  400. "Content-Type: text/plain; "
  401. "charset=UTF-8; format=fixed\n"
  402. "Content-Transfer-Encoding: 8bit\n\n",
  403. extra_headers ? extra_headers : "",
  404. mime_boundary_leader, opt->mime_boundary,
  405. mime_boundary_leader, opt->mime_boundary);
  406. extra_headers = subject_buffer.buf;
  407. if (opt->numbered_files)
  408. strbuf_addf(&filename, "%d", opt->nr);
  409. else
  410. fmt_output_commit(&filename, commit, opt);
  411. strbuf_addf(&buffer,
  412. "\n--%s%s\n"
  413. "Content-Type: text/x-patch;"
  414. " name=\"%s\"\n"
  415. "Content-Transfer-Encoding: 8bit\n"
  416. "Content-Disposition: %s;"
  417. " filename=\"%s\"\n\n",
  418. mime_boundary_leader, opt->mime_boundary,
  419. filename.buf,
  420. opt->no_inline ? "attachment" : "inline",
  421. filename.buf);
  422. opt->diffopt.stat_sep = buffer.buf;
  423. strbuf_release(&filename);
  424. }
  425. *extra_headers_p = extra_headers;
  426. }
  427. static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
  428. {
  429. const char *color, *reset, *eol;
  430. color = diff_get_color_opt(&opt->diffopt,
  431. status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
  432. reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
  433. while (*bol) {
  434. eol = strchrnul(bol, '\n');
  435. fprintf(opt->diffopt.file, "%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
  436. *eol ? "\n" : "");
  437. graph_show_oneline(opt->graph);
  438. bol = (*eol) ? (eol + 1) : eol;
  439. }
  440. }
  441. static void show_signature(struct rev_info *opt, struct commit *commit)
  442. {
  443. struct strbuf payload = STRBUF_INIT;
  444. struct strbuf signature = STRBUF_INIT;
  445. struct signature_check sigc = { 0 };
  446. int status;
  447. if (parse_signed_commit(commit, &payload, &signature) <= 0)
  448. goto out;
  449. status = check_signature(payload.buf, payload.len, signature.buf,
  450. signature.len, &sigc);
  451. if (status && !sigc.gpg_output)
  452. show_sig_lines(opt, status, "No signature\n");
  453. else
  454. show_sig_lines(opt, status, sigc.gpg_output);
  455. signature_check_clear(&sigc);
  456. out:
  457. strbuf_release(&payload);
  458. strbuf_release(&signature);
  459. }
  460. static int which_parent(const struct object_id *oid, const struct commit *commit)
  461. {
  462. int nth;
  463. const struct commit_list *parent;
  464. for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
  465. if (oideq(&parent->item->object.oid, oid))
  466. return nth;
  467. nth++;
  468. }
  469. return -1;
  470. }
  471. static int is_common_merge(const struct commit *commit)
  472. {
  473. return (commit->parents
  474. && commit->parents->next
  475. && !commit->parents->next->next);
  476. }
  477. static int show_one_mergetag(struct commit *commit,
  478. struct commit_extra_header *extra,
  479. void *data)
  480. {
  481. struct rev_info *opt = (struct rev_info *)data;
  482. struct object_id oid;
  483. struct tag *tag;
  484. struct strbuf verify_message;
  485. struct signature_check sigc = { 0 };
  486. int status, nth;
  487. size_t payload_size;
  488. hash_object_file(the_hash_algo, extra->value, extra->len,
  489. type_name(OBJ_TAG), &oid);
  490. tag = lookup_tag(the_repository, &oid);
  491. if (!tag)
  492. return -1; /* error message already given */
  493. strbuf_init(&verify_message, 256);
  494. if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
  495. strbuf_addstr(&verify_message, "malformed mergetag\n");
  496. else if (is_common_merge(commit) &&
  497. oideq(&tag->tagged->oid,
  498. &commit->parents->next->item->object.oid))
  499. strbuf_addf(&verify_message,
  500. "merged tag '%s'\n", tag->tag);
  501. else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
  502. strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
  503. tag->tag, oid_to_hex(&tag->tagged->oid));
  504. else
  505. strbuf_addf(&verify_message,
  506. "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
  507. payload_size = parse_signature(extra->value, extra->len);
  508. status = -1;
  509. if (extra->len > payload_size) {
  510. /* could have a good signature */
  511. status = check_signature(extra->value, payload_size,
  512. extra->value + payload_size,
  513. extra->len - payload_size, &sigc);
  514. if (sigc.gpg_output)
  515. strbuf_addstr(&verify_message, sigc.gpg_output);
  516. else
  517. strbuf_addstr(&verify_message, "No signature\n");
  518. signature_check_clear(&sigc);
  519. /* otherwise we couldn't verify, which is shown as bad */
  520. }
  521. show_sig_lines(opt, status, verify_message.buf);
  522. strbuf_release(&verify_message);
  523. return 0;
  524. }
  525. static int show_mergetag(struct rev_info *opt, struct commit *commit)
  526. {
  527. return for_each_mergetag(show_one_mergetag, commit, opt);
  528. }
  529. static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
  530. {
  531. const char *x = opt->shown_dashes ? "\n" : "---\n";
  532. if (sb)
  533. strbuf_addstr(sb, x);
  534. else
  535. fputs(x, opt->diffopt.file);
  536. opt->shown_dashes = 1;
  537. }
  538. void show_log(struct rev_info *opt)
  539. {
  540. struct strbuf msgbuf = STRBUF_INIT;
  541. struct log_info *log = opt->loginfo;
  542. struct commit *commit = log->commit, *parent = log->parent;
  543. int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz;
  544. const char *extra_headers = opt->extra_headers;
  545. struct pretty_print_context ctx = {0};
  546. opt->loginfo = NULL;
  547. if (!opt->verbose_header) {
  548. graph_show_commit(opt->graph);
  549. if (!opt->graph)
  550. put_revision_mark(opt, commit);
  551. fputs(find_unique_abbrev(&commit->object.oid, abbrev_commit), opt->diffopt.file);
  552. if (opt->print_parents)
  553. show_parents(commit, abbrev_commit, opt->diffopt.file);
  554. if (opt->children.name)
  555. show_children(opt, commit, abbrev_commit);
  556. show_decorations(opt, commit);
  557. if (opt->graph && !graph_is_commit_finished(opt->graph)) {
  558. putc('\n', opt->diffopt.file);
  559. graph_show_remainder(opt->graph);
  560. }
  561. putc(opt->diffopt.line_termination, opt->diffopt.file);
  562. return;
  563. }
  564. /*
  565. * If use_terminator is set, we already handled any record termination
  566. * at the end of the last record.
  567. * Otherwise, add a diffopt.line_termination character before all
  568. * entries but the first. (IOW, as a separator between entries)
  569. */
  570. if (opt->shown_one && !opt->use_terminator) {
  571. /*
  572. * If entries are separated by a newline, the output
  573. * should look human-readable. If the last entry ended
  574. * with a newline, print the graph output before this
  575. * newline. Otherwise it will end up as a completely blank
  576. * line and will look like a gap in the graph.
  577. *
  578. * If the entry separator is not a newline, the output is
  579. * primarily intended for programmatic consumption, and we
  580. * never want the extra graph output before the entry
  581. * separator.
  582. */
  583. if (opt->diffopt.line_termination == '\n' &&
  584. !opt->missing_newline)
  585. graph_show_padding(opt->graph);
  586. putc(opt->diffopt.line_termination, opt->diffopt.file);
  587. }
  588. opt->shown_one = 1;
  589. /*
  590. * If the history graph was requested,
  591. * print the graph, up to this commit's line
  592. */
  593. graph_show_commit(opt->graph);
  594. /*
  595. * Print header line of header..
  596. */
  597. if (cmit_fmt_is_mail(opt->commit_format)) {
  598. log_write_email_headers(opt, commit, &extra_headers,
  599. &ctx.need_8bit_cte, 1);
  600. ctx.rev = opt;
  601. ctx.print_email_subject = 1;
  602. } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
  603. fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), opt->diffopt.file);
  604. if (opt->commit_format != CMIT_FMT_ONELINE)
  605. fputs("commit ", opt->diffopt.file);
  606. if (!opt->graph)
  607. put_revision_mark(opt, commit);
  608. fputs(find_unique_abbrev(&commit->object.oid,
  609. abbrev_commit),
  610. opt->diffopt.file);
  611. if (opt->print_parents)
  612. show_parents(commit, abbrev_commit, opt->diffopt.file);
  613. if (opt->children.name)
  614. show_children(opt, commit, abbrev_commit);
  615. if (parent)
  616. fprintf(opt->diffopt.file, " (from %s)",
  617. find_unique_abbrev(&parent->object.oid, abbrev_commit));
  618. fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
  619. show_decorations(opt, commit);
  620. if (opt->commit_format == CMIT_FMT_ONELINE) {
  621. putc(' ', opt->diffopt.file);
  622. } else {
  623. putc('\n', opt->diffopt.file);
  624. graph_show_oneline(opt->graph);
  625. }
  626. if (opt->reflog_info) {
  627. /*
  628. * setup_revisions() ensures that opt->reflog_info
  629. * and opt->graph cannot both be set,
  630. * so we don't need to worry about printing the
  631. * graph info here.
  632. */
  633. show_reflog_message(opt->reflog_info,
  634. opt->commit_format == CMIT_FMT_ONELINE,
  635. &opt->date_mode,
  636. opt->date_mode_explicit);
  637. if (opt->commit_format == CMIT_FMT_ONELINE)
  638. return;
  639. }
  640. }
  641. if (opt->show_signature) {
  642. show_signature(opt, commit);
  643. show_mergetag(opt, commit);
  644. }
  645. if (opt->show_notes) {
  646. int raw;
  647. struct strbuf notebuf = STRBUF_INIT;
  648. raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
  649. format_display_notes(&commit->object.oid, &notebuf,
  650. get_log_output_encoding(), raw);
  651. ctx.notes_message = strbuf_detach(&notebuf, NULL);
  652. }
  653. /*
  654. * And then the pretty-printed message itself
  655. */
  656. if (ctx.need_8bit_cte >= 0 && opt->add_signoff)
  657. ctx.need_8bit_cte =
  658. has_non_ascii(fmt_name(WANT_COMMITTER_IDENT));
  659. ctx.date_mode = opt->date_mode;
  660. ctx.date_mode_explicit = opt->date_mode_explicit;
  661. ctx.abbrev = opt->diffopt.abbrev;
  662. ctx.after_subject = extra_headers;
  663. ctx.preserve_subject = opt->preserve_subject;
  664. ctx.encode_email_headers = opt->encode_email_headers;
  665. ctx.reflog_info = opt->reflog_info;
  666. ctx.fmt = opt->commit_format;
  667. ctx.mailmap = opt->mailmap;
  668. ctx.color = opt->diffopt.use_color;
  669. ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
  670. ctx.output_encoding = get_log_output_encoding();
  671. ctx.rev = opt;
  672. if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
  673. ctx.from_ident = &opt->from_ident;
  674. if (opt->graph)
  675. ctx.graph_width = graph_width(opt->graph);
  676. pretty_print_commit(&ctx, commit, &msgbuf);
  677. if (opt->add_signoff)
  678. append_signoff(&msgbuf, 0, APPEND_SIGNOFF_DEDUP);
  679. if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
  680. ctx.notes_message && *ctx.notes_message) {
  681. if (cmit_fmt_is_mail(ctx.fmt))
  682. next_commentary_block(opt, &msgbuf);
  683. strbuf_addstr(&msgbuf, ctx.notes_message);
  684. }
  685. if (opt->show_log_size) {
  686. fprintf(opt->diffopt.file, "log size %i\n", (int)msgbuf.len);
  687. graph_show_oneline(opt->graph);
  688. }
  689. /*
  690. * Set opt->missing_newline if msgbuf doesn't
  691. * end in a newline (including if it is empty)
  692. */
  693. if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
  694. opt->missing_newline = 1;
  695. else
  696. opt->missing_newline = 0;
  697. graph_show_commit_msg(opt->graph, opt->diffopt.file, &msgbuf);
  698. if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) {
  699. if (!opt->missing_newline)
  700. graph_show_padding(opt->graph);
  701. putc(opt->diffopt.line_termination, opt->diffopt.file);
  702. }
  703. strbuf_release(&msgbuf);
  704. free(ctx.notes_message);
  705. if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
  706. struct diff_queue_struct dq;
  707. memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
  708. DIFF_QUEUE_CLEAR(&diff_queued_diff);
  709. next_commentary_block(opt, NULL);
  710. fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
  711. show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2,
  712. &opt->diffopt);
  713. memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
  714. }
  715. if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) {
  716. struct diff_queue_struct dq;
  717. struct diff_options opts;
  718. memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
  719. DIFF_QUEUE_CLEAR(&diff_queued_diff);
  720. next_commentary_block(opt, NULL);
  721. fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title);
  722. /*
  723. * Pass minimum required diff-options to range-diff; others
  724. * can be added later if deemed desirable.
  725. */
  726. diff_setup(&opts);
  727. opts.file = opt->diffopt.file;
  728. opts.use_color = opt->diffopt.use_color;
  729. diff_setup_done(&opts);
  730. show_range_diff(opt->rdiff1, opt->rdiff2,
  731. opt->creation_factor, 1, &opts, NULL);
  732. memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
  733. }
  734. }
  735. int log_tree_diff_flush(struct rev_info *opt)
  736. {
  737. opt->shown_dashes = 0;
  738. diffcore_std(&opt->diffopt);
  739. if (diff_queue_is_empty()) {
  740. int saved_fmt = opt->diffopt.output_format;
  741. opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
  742. diff_flush(&opt->diffopt);
  743. opt->diffopt.output_format = saved_fmt;
  744. return 0;
  745. }
  746. if (opt->loginfo && !opt->no_commit_id) {
  747. show_log(opt);
  748. if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
  749. opt->verbose_header &&
  750. opt->commit_format != CMIT_FMT_ONELINE &&
  751. !commit_format_is_empty(opt->commit_format)) {
  752. /*
  753. * When showing a verbose header (i.e. log message),
  754. * and not in --pretty=oneline format, we would want
  755. * an extra newline between the end of log and the
  756. * diff/diffstat output for readability.
  757. */
  758. int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
  759. if (opt->diffopt.output_prefix) {
  760. struct strbuf *msg = NULL;
  761. msg = opt->diffopt.output_prefix(&opt->diffopt,
  762. opt->diffopt.output_prefix_data);
  763. fwrite(msg->buf, msg->len, 1, opt->diffopt.file);
  764. }
  765. /*
  766. * We may have shown three-dashes line early
  767. * between generated commentary (notes, etc.)
  768. * and the log message, in which case we only
  769. * want a blank line after the commentary
  770. * without (an extra) three-dashes line.
  771. * Otherwise, we show the three-dashes line if
  772. * we are showing the patch with diffstat, but
  773. * in that case, there is no extra blank line
  774. * after the three-dashes line.
  775. */
  776. if (!opt->shown_dashes &&
  777. (pch & opt->diffopt.output_format) == pch)
  778. fprintf(opt->diffopt.file, "---");
  779. putc('\n', opt->diffopt.file);
  780. }
  781. }
  782. diff_flush(&opt->diffopt);
  783. return 1;
  784. }
  785. static int do_diff_combined(struct rev_info *opt, struct commit *commit)
  786. {
  787. diff_tree_combined_merge(commit, opt);
  788. return !opt->loginfo;
  789. }
  790. /*
  791. * Show the diff of a commit.
  792. *
  793. * Return true if we printed any log info messages
  794. */
  795. static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log)
  796. {
  797. int showed_log;
  798. struct commit_list *parents;
  799. struct object_id *oid;
  800. if (!opt->diff && !opt->diffopt.flags.exit_with_status)
  801. return 0;
  802. parse_commit_or_die(commit);
  803. oid = get_commit_tree_oid(commit);
  804. /* Root commit? */
  805. parents = get_saved_parents(opt, commit);
  806. if (!parents) {
  807. if (opt->show_root_diff) {
  808. diff_root_tree_oid(oid, "", &opt->diffopt);
  809. log_tree_diff_flush(opt);
  810. }
  811. return !opt->loginfo;
  812. }
  813. /* More than one parent? */
  814. if (parents->next) {
  815. if (opt->ignore_merges)
  816. return 0;
  817. else if (opt->combine_merges)
  818. return do_diff_combined(opt, commit);
  819. else if (!opt->first_parent_only) {
  820. /* If we show multiple diffs, show the parent info */
  821. log->parent = parents->item;
  822. }
  823. }
  824. showed_log = 0;
  825. for (;;) {
  826. struct commit *parent = parents->item;
  827. parse_commit_or_die(parent);
  828. diff_tree_oid(get_commit_tree_oid(parent),
  829. oid, "", &opt->diffopt);
  830. log_tree_diff_flush(opt);
  831. showed_log |= !opt->loginfo;
  832. /* Set up the log info for the next parent, if any.. */
  833. parents = parents->next;
  834. if (!parents || opt->first_parent_only)
  835. break;
  836. log->parent = parents->item;
  837. opt->loginfo = log;
  838. }
  839. return showed_log;
  840. }
  841. int log_tree_commit(struct rev_info *opt, struct commit *commit)
  842. {
  843. struct log_info log;
  844. int shown, close_file = opt->diffopt.close_file;
  845. log.commit = commit;
  846. log.parent = NULL;
  847. opt->loginfo = &log;
  848. opt->diffopt.close_file = 0;
  849. if (opt->line_level_traverse)
  850. return line_log_print(opt, commit);
  851. if (opt->track_linear && !opt->linear && !opt->reverse_output_stage)
  852. fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
  853. shown = log_tree_diff(opt, commit, &log);
  854. if (!shown && opt->loginfo && opt->always_show_header) {
  855. log.parent = NULL;
  856. show_log(opt);
  857. shown = 1;
  858. }
  859. if (opt->track_linear && !opt->linear && opt->reverse_output_stage)
  860. fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
  861. opt->loginfo = NULL;
  862. maybe_flush_or_die(opt->diffopt.file, "stdout");
  863. if (close_file)
  864. fclose(opt->diffopt.file);
  865. return shown;
  866. }