]> git.ipfire.org Git - thirdparty/git.git/blobdiff - log-tree.c
Merge branch 'km/submodule-doc-use-sm-path' into maint
[thirdparty/git.git] / log-tree.c
index 4aef85331e0b696d0373cf1bdb0743a7e6b58c36..4e32638de8adc2ad28aaedd16f44281b2fbc9482 100644 (file)
@@ -1,6 +1,8 @@
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
+#include "object-store.h"
+#include "repository.h"
 #include "commit.h"
 #include "tag.h"
 #include "graph.h"
@@ -12,6 +14,9 @@
 #include "gpg-interface.h"
 #include "sequencer.h"
 #include "line-log.h"
+#include "help.h"
+#include "interdiff.h"
+#include "range-diff.h"
 
 static struct decoration name_decoration = { "object names" };
 static int decoration_loaded;
@@ -27,6 +32,15 @@ static char decoration_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_BOLD_BLUE,    /* GRAFTED */
 };
 
+static const char *color_decorate_slots[] = {
+       [DECORATION_REF_LOCAL]  = "branch",
+       [DECORATION_REF_REMOTE] = "remoteBranch",
+       [DECORATION_REF_TAG]    = "tag",
+       [DECORATION_REF_STASH]  = "stash",
+       [DECORATION_REF_HEAD]   = "HEAD",
+       [DECORATION_GRAFTED]    = "grafted",
+};
+
 static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
 {
        if (want_color(decorate_use_color))
@@ -34,34 +48,11 @@ static const char *decorate_get_color(int decorate_use_color, enum decoration_ty
        return "";
 }
 
-static int parse_decorate_color_slot(const char *slot)
-{
-       /*
-        * We're comparing with 'ignore-case' on
-        * (because config.c sets them all tolower),
-        * but let's match the letters in the literal
-        * string values here with how they are
-        * documented in Documentation/config.txt, for
-        * consistency.
-        *
-        * We love being consistent, don't we?
-        */
-       if (!strcasecmp(slot, "branch"))
-               return DECORATION_REF_LOCAL;
-       if (!strcasecmp(slot, "remoteBranch"))
-               return DECORATION_REF_REMOTE;
-       if (!strcasecmp(slot, "tag"))
-               return DECORATION_REF_TAG;
-       if (!strcasecmp(slot, "stash"))
-               return DECORATION_REF_STASH;
-       if (!strcasecmp(slot, "HEAD"))
-               return DECORATION_REF_HEAD;
-       return -1;
-}
+define_list_config_array(color_decorate_slots);
 
 int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
 {
-       int slot = parse_decorate_color_slot(slot_name);
+       int slot = LOOKUP_CONFIG(color_decorate_slots, slot_name);
        if (slot < 0)
                return 0;
        if (!value)
@@ -86,6 +77,7 @@ void add_name_decoration(enum decoration_type type, const char *name, struct obj
 
 const struct name_decoration *get_name_decoration(const struct object *obj)
 {
+       load_ref_decorations(NULL, DECORATE_SHORT_REFS);
        return lookup_decoration(&name_decoration, obj);
 }
 
@@ -103,20 +95,20 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 
        if (starts_with(refname, git_replace_ref_base)) {
                struct object_id original_oid;
-               if (!check_replace_refs)
+               if (!read_replace_refs)
                        return 0;
                if (get_oid_hex(refname + strlen(git_replace_ref_base),
                                &original_oid)) {
                        warning("invalid replace ref %s", refname);
                        return 0;
                }
-               obj = parse_object(&original_oid);
+               obj = parse_object(the_repository, &original_oid);
                if (obj)
                        add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
                return 0;
        }
 
-       obj = parse_object(oid);
+       obj = parse_object(the_repository, oid);
        if (!obj)
                return 0;
 
@@ -137,7 +129,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
                if (!obj)
                        break;
                if (!obj->parsed)
-                       parse_object(&obj->oid);
+                       parse_object(the_repository, &obj->oid);
                add_name_decoration(DECORATION_REF_TAG, refname, obj);
        }
        return 0;
@@ -145,7 +137,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 
 static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
 {
-       struct commit *commit = lookup_commit(&graft->oid);
+       struct commit *commit = lookup_commit(the_repository, &graft->oid);
        if (!commit)
                return 0;
        add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
@@ -295,8 +287,12 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
 
-       if (opt->show_source && commit->util)
-               fprintf(opt->diffopt.file, "\t%s", (char *) commit->util);
+       if (opt->sources) {
+               char **slot = revision_sources_peek(opt->sources, commit);
+
+               if (slot && *slot)
+                       fprintf(opt->diffopt.file, "\t%s", *slot);
+       }
        if (!opt->show_decorations)
                return;
        format_decorations(&sb, commit, opt->diffopt.use_color);
@@ -453,22 +449,22 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
 {
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
-       struct strbuf gpg_output = STRBUF_INIT;
+       struct signature_check sigc = { 0 };
        int status;
 
        if (parse_signed_commit(commit, &payload, &signature) <= 0)
                goto out;
 
-       status = verify_signed_buffer(payload.buf, payload.len,
-                                     signature.buf, signature.len,
-                                     &gpg_output, NULL);
-       if (status && !gpg_output.len)
-               strbuf_addstr(&gpg_output, "No signature\n");
-
-       show_sig_lines(opt, status, gpg_output.buf);
+       status = check_signature(payload.buf, payload.len, signature.buf,
+                                signature.len, &sigc);
+       if (status && sigc.result == 'N')
+               show_sig_lines(opt, status, "No signature\n");
+       else {
+               show_sig_lines(opt, status, sigc.gpg_output);
+               signature_check_clear(&sigc);
+       }
 
  out:
-       strbuf_release(&gpg_output);
        strbuf_release(&payload);
        strbuf_release(&signature);
 }
@@ -479,7 +475,7 @@ static int which_parent(const struct object_id *oid, const struct commit *commit
        const struct commit_list *parent;
 
        for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
-               if (!oidcmp(&parent->item->object.oid, oid))
+               if (oideq(&parent->item->object.oid, oid))
                        return nth;
                nth++;
        }
@@ -501,20 +497,21 @@ static int show_one_mergetag(struct commit *commit,
        struct object_id oid;
        struct tag *tag;
        struct strbuf verify_message;
+       struct signature_check sigc = { 0 };
        int status, nth;
        size_t payload_size, gpg_message_offset;
 
        hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &oid);
-       tag = lookup_tag(&oid);
+       tag = lookup_tag(the_repository, &oid);
        if (!tag)
                return -1; /* error message already given */
 
        strbuf_init(&verify_message, 256);
-       if (parse_tag_buffer(tag, extra->value, extra->len))
+       if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
                strbuf_addstr(&verify_message, "malformed mergetag\n");
        else if (is_common_merge(commit) &&
-                !oidcmp(&tag->tagged->oid,
-                         &commit->parents->next->item->object.oid))
+                oideq(&tag->tagged->oid,
+                      &commit->parents->next->item->object.oid))
                strbuf_addf(&verify_message,
                            "merged tag '%s'\n", tag->tag);
        else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
@@ -529,12 +526,13 @@ static int show_one_mergetag(struct commit *commit,
        status = -1;
        if (extra->len > payload_size) {
                /* could have a good signature */
-               if (!verify_signed_buffer(extra->value, payload_size,
-                                         extra->value + payload_size,
-                                         extra->len - payload_size,
-                                         &verify_message, NULL))
+               if (!check_signature(extra->value, payload_size,
+                                    extra->value + payload_size,
+                                    extra->len - payload_size, &sigc)) {
+                       strbuf_addstr(&verify_message, sigc.gpg_output);
+                       signature_check_clear(&sigc);
                        status = 0; /* good */
-               else if (verify_message.len <= gpg_message_offset)
+               else if (verify_message.len <= gpg_message_offset)
                        strbuf_addstr(&verify_message, "No signature\n");
                /* otherwise we couldn't verify, which is shown as bad */
        }
@@ -549,12 +547,22 @@ static int show_mergetag(struct rev_info *opt, struct commit *commit)
        return for_each_mergetag(show_one_mergetag, commit, opt);
 }
 
+static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
+{
+       const char *x = opt->shown_dashes ? "\n" : "---\n";
+       if (sb)
+               strbuf_addstr(sb, x);
+       else
+               fputs(x, opt->diffopt.file);
+       opt->shown_dashes = 1;
+}
+
 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 : GIT_SHA1_HEXSZ;
+       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};
 
@@ -672,9 +680,7 @@ void show_log(struct rev_info *opt)
                raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
                format_display_notes(&commit->object.oid, &notebuf,
                                     get_log_output_encoding(), raw);
-               ctx.notes_message = notebuf.len
-                       ? strbuf_detach(&notebuf, NULL)
-                       : xcalloc(1, 1);
+               ctx.notes_message = strbuf_detach(&notebuf, NULL);
        }
 
        /*
@@ -682,8 +688,7 @@ void show_log(struct rev_info *opt)
         */
        if (ctx.need_8bit_cte >= 0 && opt->add_signoff)
                ctx.need_8bit_cte =
-                       has_non_ascii(fmt_name(getenv("GIT_COMMITTER_NAME"),
-                                              getenv("GIT_COMMITTER_EMAIL")));
+                       has_non_ascii(fmt_name(WANT_COMMITTER_IDENT));
        ctx.date_mode = opt->date_mode;
        ctx.date_mode_explicit = opt->date_mode_explicit;
        ctx.abbrev = opt->diffopt.abbrev;
@@ -695,6 +700,7 @@ void show_log(struct rev_info *opt)
        ctx.color = opt->diffopt.use_color;
        ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
        ctx.output_encoding = get_log_output_encoding();
+       ctx.rev = opt;
        if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
                ctx.from_ident = &opt->from_ident;
        if (opt->graph)
@@ -706,10 +712,8 @@ void show_log(struct rev_info *opt)
 
        if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
            ctx.notes_message && *ctx.notes_message) {
-               if (cmit_fmt_is_mail(ctx.fmt)) {
-                       strbuf_addstr(&msgbuf, "---\n");
-                       opt->shown_dashes = 1;
-               }
+               if (cmit_fmt_is_mail(ctx.fmt))
+                       next_commentary_block(opt, &msgbuf);
                strbuf_addstr(&msgbuf, ctx.notes_message);
        }
 
@@ -736,6 +740,42 @@ 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, 2);
+
+               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;
+
+               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.
+                */
+               diff_setup(&opts);
+               opts.file = opt->diffopt.file;
+               opts.use_color = opt->diffopt.use_color;
+               diff_setup_done(&opts);
+               show_range_diff(opt->rdiff1, opt->rdiff2,
+                               opt->creation_factor, 1, &opts, NULL);
+
+               memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
+       }
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
@@ -773,9 +813,10 @@ int log_tree_diff_flush(struct rev_info *opt)
 
                        /*
                         * We may have shown three-dashes line early
-                        * between notes and the log message, in which
-                        * case we only want a blank line after the
-                        * notes without (an extra) three-dashes line.
+                        * between generated commentary (notes, etc.)
+                        * and the log message, in which case we only
+                        * want a blank line after the commentary
+                        * without (an extra) three-dashes line.
                         * Otherwise, we show the three-dashes line if
                         * we are showing the patch with diffstat, but
                         * in that case, there is no extra blank line