diff options
Diffstat (limited to 'log-tree.c')
-rw-r--r-- | log-tree.c | 269 |
1 files changed, 165 insertions, 104 deletions
diff --git a/log-tree.c b/log-tree.c index 208c69cbb7..83cc4b1cfb 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,7 +1,10 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit-reach.h" #include "config.h" #include "diff.h" +#include "diffcore.h" #include "environment.h" #include "hex.h" #include "object-name.h" @@ -28,6 +31,7 @@ #include "tree.h" #include "wildmatch.h" #include "write-or-die.h" +#include "pager.h" static struct decoration name_decoration = { "object names" }; static int decoration_loaded; @@ -142,7 +146,7 @@ static int ref_filter_match(const char *refname, return 1; } -static int add_ref_decoration(const char *refname, const struct object_id *oid, +static int add_ref_decoration(const char *refname, const char *referent UNUSED, const struct object_id *oid, int flags UNUSED, void *cb_data) { @@ -228,15 +232,43 @@ void load_ref_decorations(struct decoration_filter *filter, int flags) for_each_string_list_item(item, filter->exclude_ref_config_pattern) { normalize_glob_ref(item, NULL, item->string); } + + /* normalize_glob_ref duplicates the strings */ + filter->exclude_ref_pattern->strdup_strings = 1; + filter->include_ref_pattern->strdup_strings = 1; + filter->exclude_ref_config_pattern->strdup_strings = 1; } decoration_loaded = 1; decoration_flags = flags; - for_each_ref(add_ref_decoration, filter); - head_ref(add_ref_decoration, filter); + refs_for_each_ref(get_main_ref_store(the_repository), + add_ref_decoration, filter); + refs_head_ref(get_main_ref_store(the_repository), + add_ref_decoration, filter); for_each_commit_graft(add_graft_decoration, filter); } } +void load_branch_decorations(void) +{ + if (!decoration_loaded) { + struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP; + struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP; + struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP; + struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude, + .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; + + string_list_append(&decorate_refs_include, "refs/heads/"); + load_ref_decorations(&decoration_filter, 0); + + string_list_clear(&decorate_refs_exclude, 0); + string_list_clear(&decorate_refs_exclude_config, 0); + string_list_clear(&decorate_refs_include, 0); + } +} + static void show_parents(struct commit *commit, int abbrev, FILE *file) { struct commit_list *p; @@ -276,7 +308,8 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d return NULL; /* Now resolve and find the matching current branch */ - branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags); + branch_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + "HEAD", 0, NULL, &rru_flags); if (!branch_name || !(rru_flags & REF_ISSYMREF)) return NULL; @@ -303,26 +336,43 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio /* * The caller makes sure there is no funny color before calling. - * format_decorations_extended makes sure the same after return. + * format_decorations ensures the same after return. */ -void format_decorations_extended(struct strbuf *sb, +void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color, - const char *prefix, - const char *separator, - const char *suffix) + const struct decoration_options *opts) { const struct name_decoration *decoration; const struct name_decoration *current_and_HEAD; - const char *color_commit = - diff_get_color(use_color, DIFF_COMMIT); - const char *color_reset = - decorate_get_color(use_color, DECORATION_NONE); + const char *color_commit, *color_reset; + + const char *prefix = " ("; + const char *suffix = ")"; + const char *separator = ", "; + const char *pointer = " -> "; + const char *tag = "tag: "; decoration = get_name_decoration(&commit->object); if (!decoration) return; + if (opts) { + if (opts->prefix) + prefix = opts->prefix; + if (opts->suffix) + suffix = opts->suffix; + if (opts->separator) + separator = opts->separator; + if (opts->pointer) + pointer = opts->pointer; + if (opts->tag) + tag = opts->tag; + } + + color_commit = diff_get_color(use_color, DIFF_COMMIT); + color_reset = decorate_get_color(use_color, DECORATION_NONE); + current_and_HEAD = current_pointed_by_HEAD(decoration); while (decoration) { /* @@ -331,31 +381,44 @@ void format_decorations_extended(struct strbuf *sb, * appeared, skipping the entry for current. */ if (decoration != current_and_HEAD) { - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, prefix); - strbuf_addstr(sb, color_reset); - strbuf_addstr(sb, decorate_get_color(use_color, decoration->type)); - if (decoration->type == DECORATION_REF_TAG) - strbuf_addstr(sb, "tag: "); + const char *color = + decorate_get_color(use_color, decoration->type); + + if (*prefix) { + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, prefix); + strbuf_addstr(sb, color_reset); + } + + if (*tag && decoration->type == DECORATION_REF_TAG) { + strbuf_addstr(sb, color); + strbuf_addstr(sb, tag); + strbuf_addstr(sb, color_reset); + } + strbuf_addstr(sb, color); show_name(sb, decoration); + strbuf_addstr(sb, color_reset); if (current_and_HEAD && decoration->type == DECORATION_REF_HEAD) { - strbuf_addstr(sb, " -> "); + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, pointer); strbuf_addstr(sb, color_reset); strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type)); show_name(sb, current_and_HEAD); + strbuf_addstr(sb, color_reset); } - strbuf_addstr(sb, color_reset); prefix = separator; } decoration = decoration->next; } - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, suffix); - strbuf_addstr(sb, color_reset); + if (*suffix) { + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, suffix); + strbuf_addstr(sb, color_reset); + } } void show_decorations(struct rev_info *opt, struct commit *commit) @@ -370,21 +433,11 @@ void show_decorations(struct rev_info *opt, struct commit *commit) } if (!opt->show_decorations) return; - format_decorations(&sb, commit, opt->diffopt.use_color); + format_decorations(&sb, commit, opt->diffopt.use_color, NULL); fputs(sb.buf, opt->diffopt.file); strbuf_release(&sb); } -static unsigned int digits_in_number(unsigned int number) -{ - unsigned int i = 10, result = 1; - while (i <= number) { - i *= 10; - result++; - } - return result; -} - void fmt_output_subject(struct strbuf *filename, const char *subject, struct rev_info *info) @@ -428,7 +481,7 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt) strbuf_addf(sb, "Subject: [%s%s%0*d/%d] ", opt->subject_prefix, *opt->subject_prefix ? " " : "", - digits_in_number(opt->total), + decimal_width(opt->total), opt->nr, opt->total); } else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) { strbuf_addf(sb, "Subject: [%s] ", @@ -439,16 +492,19 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt) } void log_write_email_headers(struct rev_info *opt, struct commit *commit, - const char **extra_headers_p, + char **extra_headers_p, int *need_8bit_cte_p, int maybe_multipart) { - const char *extra_headers = opt->extra_headers; + struct strbuf headers = STRBUF_INIT; const char *name = oid_to_hex(opt->zero_commit ? null_oid() : &commit->object.oid); *need_8bit_cte_p = 0; /* unknown */ + if (opt->extra_headers && *opt->extra_headers) + strbuf_addstr(&headers, opt->extra_headers); + fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name); graph_show_oneline(opt->graph); if (opt->message_id) { @@ -465,16 +521,13 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, graph_show_oneline(opt->graph); } if (opt->mime_boundary && maybe_multipart) { - static struct strbuf subject_buffer = STRBUF_INIT; static struct strbuf buffer = STRBUF_INIT; struct strbuf filename = STRBUF_INIT; *need_8bit_cte_p = -1; /* NEVER */ - strbuf_reset(&subject_buffer); strbuf_reset(&buffer); - strbuf_addf(&subject_buffer, - "%s" + strbuf_addf(&headers, "MIME-Version: 1.0\n" "Content-Type: multipart/mixed;" " boundary=\"%s%s\"\n" @@ -485,10 +538,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, "Content-Type: text/plain; " "charset=UTF-8; format=fixed\n" "Content-Transfer-Encoding: 8bit\n\n", - extra_headers ? extra_headers : "", mime_boundary_leader, opt->mime_boundary, mime_boundary_leader, opt->mime_boundary); - extra_headers = subject_buffer.buf; if (opt->numbered_files) strbuf_addf(&filename, "%d", opt->nr); @@ -508,7 +559,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, opt->diffopt.stat_sep = buffer.buf; strbuf_release(&filename); } - *extra_headers_p = extra_headers; + *extra_headers_p = headers.len ? strbuf_detach(&headers, NULL) : NULL; } static void show_sig_lines(struct rev_info *opt, int status, const char *bol) @@ -641,13 +692,57 @@ static void next_commentary_block(struct rev_info *opt, struct strbuf *sb) opt->shown_dashes = 1; } +static void show_diff_of_diff(struct rev_info *opt) +{ + if (!cmit_fmt_is_mail(opt->commit_format)) + return; + + if (opt->idiff_oid1) { + struct diff_queue_struct dq; + + memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); + diff_queue_init(&diff_queued_diff); + + fprintf_ln(opt->diffopt.file, "\n%s", opt->idiff_title); + show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2, + &opt->diffopt); + + memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); + } + + if (opt->rdiff1) { + struct diff_queue_struct dq; + struct diff_options opts; + struct range_diff_options range_diff_opts = { + .creation_factor = opt->creation_factor, + .dual_color = 1, + .diffopt = &opts + }; + + memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); + diff_queue_init(&diff_queued_diff); + + fprintf_ln(opt->diffopt.file, "\n%s", opt->rdiff_title); + /* + * Pass minimum required diff-options to range-diff; others + * can be added later if deemed desirable. + */ + repo_diff_setup(the_repository, &opts); + opts.file = opt->diffopt.file; + opts.use_color = opt->diffopt.use_color; + diff_setup_done(&opts); + show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts); + + memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); + } +} + void show_log(struct rev_info *opt) { struct strbuf msgbuf = STRBUF_INIT; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz; - const char *extra_headers = opt->extra_headers; struct pretty_print_context ctx = {0}; opt->loginfo = NULL; @@ -708,10 +803,9 @@ void show_log(struct rev_info *opt) */ if (cmit_fmt_is_mail(opt->commit_format)) { - log_write_email_headers(opt, commit, &extra_headers, + log_write_email_headers(opt, commit, &ctx.after_subject, &ctx.need_8bit_cte, 1); ctx.rev = opt; - ctx.print_email_subject = 1; } else if (opt->commit_format != CMIT_FMT_USERFORMAT) { fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), opt->diffopt.file); if (opt->commit_format != CMIT_FMT_ONELINE) @@ -746,7 +840,7 @@ void show_log(struct rev_info *opt) */ show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, - &opt->date_mode, + opt->date_mode, opt->date_mode_explicit); if (opt->commit_format == CMIT_FMT_ONELINE) return; @@ -777,7 +871,6 @@ void show_log(struct rev_info *opt) ctx.date_mode = opt->date_mode; ctx.date_mode_explicit = opt->date_mode_explicit; ctx.abbrev = opt->diffopt.abbrev; - ctx.after_subject = extra_headers; ctx.preserve_subject = opt->preserve_subject; ctx.encode_email_headers = opt->encode_email_headers; ctx.reflog_info = opt->reflog_info; @@ -826,47 +919,7 @@ void show_log(struct rev_info *opt) strbuf_release(&msgbuf); free(ctx.notes_message); - - if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) { - struct diff_queue_struct dq; - - memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); - DIFF_QUEUE_CLEAR(&diff_queued_diff); - - next_commentary_block(opt, NULL); - fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title); - show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2, - &opt->diffopt); - - memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); - } - - if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) { - struct diff_queue_struct dq; - struct diff_options opts; - struct range_diff_options range_diff_opts = { - .creation_factor = opt->creation_factor, - .dual_color = 1, - .diffopt = &opts - }; - - memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); - DIFF_QUEUE_CLEAR(&diff_queued_diff); - - next_commentary_block(opt, NULL); - fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title); - /* - * Pass minimum required diff-options to range-diff; others - * can be added later if deemed desirable. - */ - repo_diff_setup(the_repository, &opts); - opts.file = opt->diffopt.file; - opts.use_color = opt->diffopt.use_color; - diff_setup_done(&opts); - show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts); - - memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); - } + free(ctx.after_subject); } int log_tree_diff_flush(struct rev_info *opt) @@ -895,12 +948,7 @@ int log_tree_diff_flush(struct rev_info *opt) * diff/diffstat output for readability. */ int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; - if (opt->diffopt.output_prefix) { - struct strbuf *msg = NULL; - msg = opt->diffopt.output_prefix(&opt->diffopt, - opt->diffopt.output_prefix_data); - fwrite(msg->buf, msg->len, 1, opt->diffopt.file); - } + fputs(diff_line_prefix(&opt->diffopt), opt->diffopt.file); /* * We may have shown three-dashes line early @@ -980,7 +1028,7 @@ static int do_remerge_diff(struct rev_info *opt, struct object_id *oid) { struct merge_options o; - struct commit_list *bases; + struct commit_list *bases = NULL; struct merge_result res = {0}; struct pretty_print_context ctx = {0}; struct commit *parent1 = parents->item; @@ -988,8 +1036,19 @@ static int do_remerge_diff(struct rev_info *opt, struct strbuf parent1_desc = STRBUF_INIT; struct strbuf parent2_desc = STRBUF_INIT; + /* + * Lazily prepare a temporary object directory and rotate it + * into the alternative object store list as the primary. + */ + if (opt->remerge_diff && !opt->remerge_objdir) { + opt->remerge_objdir = tmp_objdir_create("remerge-diff"); + if (!opt->remerge_objdir) + return error(_("unable to create temporary object directory")); + tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1); + } + /* Setup merge options */ - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.show_rename_progress = 0; o.record_conflict_msgs_as_headers = 1; o.msg_header_prefix = "remerge"; @@ -1005,7 +1064,8 @@ static int do_remerge_diff(struct rev_info *opt, /* Parse the relevant commits and get the merge bases */ parse_commit_or_die(parent1); parse_commit_or_die(parent2); - bases = repo_get_merge_bases(the_repository, parent1, parent2); + if (repo_get_merge_bases(the_repository, parent1, parent2, &bases) < 0) + exit(128); /* Re-merge the parents */ merge_incore_recursive(&o, bases, parent1, parent2, &res); @@ -1016,16 +1076,14 @@ static int do_remerge_diff(struct rev_info *opt, log_tree_diff_flush(opt); /* Cleanup */ + free_commit_list(bases); cleanup_additional_headers(&opt->diffopt); strbuf_release(&parent1_desc); strbuf_release(&parent2_desc); merge_finalize(&o, &res); /* Clean up the contents of the temporary object directory */ - if (opt->remerge_objdir) - tmp_objdir_discard_objects(opt->remerge_objdir); - else - BUG("did a remerge diff without remerge_objdir?!?"); + tmp_objdir_discard_objects(opt->remerge_objdir); return !opt->loginfo; } @@ -1134,9 +1192,12 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit) } if (opt->track_linear && !opt->linear && opt->reverse_output_stage) fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar); + if (shown) + show_diff_of_diff(opt); opt->loginfo = NULL; maybe_flush_or_die(opt->diffopt.file, "stdout"); opt->diffopt.no_free = no_free; + diff_free(&opt->diffopt); return shown; } |