Imported Upstream version 2.12.1
[platform/upstream/git.git] / log-tree.c
index 10e6844..8c24157 100644 (file)
 #include "sequencer.h"
 #include "line-log.h"
 
-struct decoration name_decoration = { "object names" };
-
-enum decoration_type {
-       DECORATION_NONE = 0,
-       DECORATION_REF_LOCAL,
-       DECORATION_REF_REMOTE,
-       DECORATION_REF_TAG,
-       DECORATION_REF_STASH,
-       DECORATION_REF_HEAD,
-       DECORATION_GRAFTED,
-};
+static struct decoration name_decoration = { "object names" };
+static int decoration_loaded;
+static int decoration_flags;
 
 static char decoration_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RESET,
@@ -66,15 +58,14 @@ static int parse_decorate_color_slot(const char *slot)
        return -1;
 }
 
-int parse_decorate_color_config(const char *var, const int ofs, const char *value)
+int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
 {
-       int slot = parse_decorate_color_slot(var + ofs);
+       int slot = parse_decorate_color_slot(slot_name);
        if (slot < 0)
                return 0;
        if (!value)
                return config_error_nonbool(var);
-       color_parse(value, var, decoration_colors[slot]);
-       return 0;
+       return color_parse(value, decoration_colors[slot]);
 }
 
 /*
@@ -84,35 +75,43 @@ int parse_decorate_color_config(const char *var, const int ofs, const char *valu
 #define decorate_get_color_opt(o, ix) \
        decorate_get_color((o)->use_color, ix)
 
-static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
 {
-       int nlen = strlen(name);
-       struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
-       memcpy(res->name, name, nlen + 1);
+       struct name_decoration *res;
+       FLEX_ALLOC_STR(res, name, name);
        res->type = type;
        res->next = add_decoration(&name_decoration, obj, res);
 }
 
-static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+const struct name_decoration *get_name_decoration(const struct object *obj)
+{
+       return lookup_decoration(&name_decoration, obj);
+}
+
+static int add_ref_decoration(const char *refname, const struct object_id *oid,
+                             int flags, void *cb_data)
 {
        struct object *obj;
        enum decoration_type type = DECORATION_NONE;
 
-       if (starts_with(refname, "refs/replace/")) {
-               unsigned char original_sha1[20];
+       assert(cb_data == NULL);
+
+       if (starts_with(refname, git_replace_ref_base)) {
+               struct object_id original_oid;
                if (!check_replace_refs)
                        return 0;
-               if (get_sha1_hex(refname + 13, original_sha1)) {
+               if (get_oid_hex(refname + strlen(git_replace_ref_base),
+                               &original_oid)) {
                        warning("invalid replace ref %s", refname);
                        return 0;
                }
-               obj = parse_object(original_sha1);
+               obj = parse_object(original_oid.hash);
                if (obj)
                        add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
                return 0;
        }
 
-       obj = parse_object(sha1);
+       obj = parse_object(oid->hash);
        if (!obj)
                return 0;
 
@@ -127,15 +126,13 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
        else if (!strcmp(refname, "HEAD"))
                type = DECORATION_REF_HEAD;
 
-       if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
-               refname = prettify_refname(refname);
        add_name_decoration(type, refname, obj);
        while (obj->type == OBJ_TAG) {
                obj = ((struct tag *)obj)->tagged;
                if (!obj)
                        break;
                if (!obj->parsed)
-                       parse_object(obj->sha1);
+                       parse_object(obj->oid.hash);
                add_name_decoration(DECORATION_REF_TAG, refname, obj);
        }
        return 0;
@@ -143,7 +140,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 
 static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
 {
-       struct commit *commit = lookup_commit(graft->sha1);
+       struct commit *commit = lookup_commit(graft->oid.hash);
        if (!commit)
                return 0;
        add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
@@ -152,21 +149,22 @@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
 
 void load_ref_decorations(int flags)
 {
-       static int loaded;
-       if (!loaded) {
-               loaded = 1;
-               for_each_ref(add_ref_decoration, &flags);
-               head_ref(add_ref_decoration, &flags);
+       if (!decoration_loaded) {
+
+               decoration_loaded = 1;
+               decoration_flags = flags;
+               for_each_ref(add_ref_decoration, NULL);
+               head_ref(add_ref_decoration, NULL);
                for_each_commit_graft(add_graft_decoration, NULL);
        }
 }
 
-static void show_parents(struct commit *commit, int abbrev)
+static void show_parents(struct commit *commit, int abbrev, FILE *file)
 {
        struct commit_list *p;
        for (p = commit->parents; p ; p = p->next) {
                struct commit *parent = p->item;
-               printf(" %s", find_unique_abbrev(parent->object.sha1, abbrev));
+               fprintf(file, " %s", find_unique_abbrev(parent->object.oid.hash, abbrev));
        }
 }
 
@@ -174,42 +172,110 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 {
        struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
        for ( ; p; p = p->next) {
-               printf(" %s", find_unique_abbrev(p->item->object.sha1, abbrev));
+               fprintf(opt->diffopt.file, " %s", find_unique_abbrev(p->item->object.oid.hash, abbrev));
        }
 }
 
 /*
- * The caller makes sure there is no funny color before
- * calling. format_decorations makes sure the same after return.
+ * Do we have HEAD in the output, and also the branch it points at?
+ * If so, find that decoration entry for that current branch.
+ */
+static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
+{
+       const struct name_decoration *list, *head = NULL;
+       const char *branch_name = NULL;
+       unsigned char unused[20];
+       int rru_flags;
+
+       /* First find HEAD */
+       for (list = decoration; list; list = list->next)
+               if (list->type == DECORATION_REF_HEAD) {
+                       head = list;
+                       break;
+               }
+       if (!head)
+               return NULL;
+
+       /* Now resolve and find the matching current branch */
+       branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
+       if (!(rru_flags & REF_ISSYMREF))
+               return NULL;
+
+       if (!starts_with(branch_name, "refs/"))
+               return NULL;
+
+       /* OK, do we have that ref in the list? */
+       for (list = decoration; list; list = list->next)
+               if ((list->type == DECORATION_REF_LOCAL) &&
+                   !strcmp(branch_name, list->name)) {
+                       return list;
+               }
+
+       return NULL;
+}
+
+static void show_name(struct strbuf *sb, const struct name_decoration *decoration)
+{
+       if (decoration_flags == DECORATE_SHORT_REFS)
+               strbuf_addstr(sb, prettify_refname(decoration->name));
+       else
+               strbuf_addstr(sb, decoration->name);
+}
+
+/*
+ * The caller makes sure there is no funny color before calling.
+ * format_decorations_extended makes sure the same after return.
  */
-void format_decorations(struct strbuf *sb,
+void format_decorations_extended(struct strbuf *sb,
                        const struct commit *commit,
-                       int use_color)
+                       int use_color,
+                       const char *prefix,
+                       const char *separator,
+                       const char *suffix)
 {
-       const char *prefix;
-       struct name_decoration *decoration;
+       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);
 
-       decoration = lookup_decoration(&name_decoration, &commit->object);
+       decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
-       prefix = " (";
+
+       current_and_HEAD = current_pointed_by_HEAD(decoration);
        while (decoration) {
-               strbuf_addstr(sb, color_commit);
-               strbuf_addstr(sb, prefix);
-               strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-               if (decoration->type == DECORATION_REF_TAG)
-                       strbuf_addstr(sb, "tag: ");
-               strbuf_addstr(sb, decoration->name);
-               strbuf_addstr(sb, color_reset);
-               prefix = ", ";
+               /*
+                * When both current and HEAD are there, only
+                * show HEAD->current where HEAD would have
+                * 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: ");
+
+                       show_name(sb, decoration);
+
+                       if (current_and_HEAD &&
+                           decoration->type == DECORATION_REF_HEAD) {
+                               strbuf_addstr(sb, " -> ");
+                               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);
+
+                       prefix = separator;
+               }
                decoration = decoration->next;
        }
        strbuf_addstr(sb, color_commit);
-       strbuf_addch(sb, ')');
+       strbuf_addstr(sb, suffix);
        strbuf_addstr(sb, color_reset);
 }
 
@@ -218,11 +284,11 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
        struct strbuf sb = STRBUF_INIT;
 
        if (opt->show_source && commit->util)
-               printf("\t%s", (char *) commit->util);
+               fprintf(opt->diffopt.file, "\t%s", (char *) commit->util);
        if (!opt->show_decorations)
                return;
        format_decorations(&sb, commit, opt->diffopt.use_color);
-       fputs(sb.buf, stdout);
+       fputs(sb.buf, opt->diffopt.file);
        strbuf_release(&sb);
 }
 
@@ -273,7 +339,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 {
        const char *subject = NULL;
        const char *extra_headers = opt->extra_headers;
-       const char *name = sha1_to_hex(commit->object.sha1);
+       const char *name = oid_to_hex(opt->zero_commit ?
+                                     &null_oid : &commit->object.oid);
 
        *need_8bit_cte_p = 0; /* unknown */
        if (opt->total > 0) {
@@ -295,18 +362,18 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                subject = "Subject: ";
        }
 
-       printf("From %s Mon Sep 17 00:00:00 2001\n", name);
+       fprintf(opt->diffopt.file, "From %s Mon Sep 17 00:00:00 2001\n", name);
        graph_show_oneline(opt->graph);
        if (opt->message_id) {
-               printf("Message-Id: <%s>\n", opt->message_id);
+               fprintf(opt->diffopt.file, "Message-Id: <%s>\n", opt->message_id);
                graph_show_oneline(opt->graph);
        }
        if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
                int i, n;
                n = opt->ref_message_ids->nr;
-               printf("In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
+               fprintf(opt->diffopt.file, "In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
                for (i = 0; i < n; i++)
-                       printf("%s<%s>\n", (i > 0 ? "\t" : "References: "),
+                       fprintf(opt->diffopt.file, "%s<%s>\n", (i > 0 ? "\t" : "References: "),
                               opt->ref_message_ids->items[i].string);
                graph_show_oneline(opt->graph);
        }
@@ -363,8 +430,9 @@ static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
        reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
        while (*bol) {
                eol = strchrnul(bol, '\n');
-               printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
+               fprintf(opt->diffopt.file, "%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
                       *eol ? "\n" : "");
+               graph_show_oneline(opt->graph);
                bol = (*eol) ? (eol + 1) : eol;
        }
 }
@@ -399,7 +467,7 @@ static int which_parent(const unsigned char *sha1, const struct commit *commit)
        const struct commit_list *parent;
 
        for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
-               if (!hashcmp(parent->item->object.sha1, sha1))
+               if (!hashcmp(parent->item->object.oid.hash, sha1))
                        return nth;
                nth++;
        }
@@ -413,10 +481,11 @@ static int is_common_merge(const struct commit *commit)
                && !commit->parents->next->next);
 }
 
-static void show_one_mergetag(struct rev_info *opt,
+static void show_one_mergetag(struct commit *commit,
                              struct commit_extra_header *extra,
-                             struct commit *commit)
+                             void *data)
 {
+       struct rev_info *opt = (struct rev_info *)data;
        unsigned char sha1[20];
        struct tag *tag;
        struct strbuf verify_message;
@@ -432,13 +501,13 @@ static void show_one_mergetag(struct rev_info *opt,
        if (parse_tag_buffer(tag, extra->value, extra->len))
                strbuf_addstr(&verify_message, "malformed mergetag\n");
        else if (is_common_merge(commit) &&
-                !hashcmp(tag->tagged->sha1,
-                         commit->parents->next->item->object.sha1))
+                !oidcmp(&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->sha1, commit)) < 0)
+       else if ((nth = which_parent(tag->tagged->oid.hash, commit)) < 0)
                strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
-                                   tag->tag, tag->tagged->sha1);
+                                   tag->tag, tag->tagged->oid.hash);
        else
                strbuf_addf(&verify_message,
                            "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
@@ -446,16 +515,17 @@ static void show_one_mergetag(struct rev_info *opt,
 
        payload_size = parse_signature(extra->value, extra->len);
        status = -1;
-       if (extra->len > payload_size)
-               if (verify_signed_buffer(extra->value, payload_size,
-                                        extra->value + payload_size,
-                                        extra->len - payload_size,
-                                        &verify_message, NULL)) {
-                       if (verify_message.len <= gpg_message_offset)
-                               strbuf_addstr(&verify_message, "No signature\n");
-                       else
-                               status = 0;
-               }
+       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))
+                       status = 0; /* good */
+               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 */
+       }
 
        show_sig_lines(opt, status, verify_message.buf);
        strbuf_release(&verify_message);
@@ -463,15 +533,7 @@ static void show_one_mergetag(struct rev_info *opt,
 
 static void show_mergetag(struct rev_info *opt, struct commit *commit)
 {
-       struct commit_extra_header *extra, *to_free;
-
-       to_free = read_commit_extra_headers(commit, NULL);
-       for (extra = to_free; extra; extra = extra->next) {
-               if (strcmp(extra->key, "mergetag"))
-                       continue; /* not a merge tag */
-               show_one_mergetag(opt, extra, commit);
-       }
-       free_commit_extra_headers(to_free);
+       for_each_mergetag(show_one_mergetag, commit, opt);
 }
 
 void show_log(struct rev_info *opt)
@@ -489,17 +551,17 @@ void show_log(struct rev_info *opt)
 
                if (!opt->graph)
                        put_revision_mark(opt, commit);
-               fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
+               fputs(find_unique_abbrev(commit->object.oid.hash, abbrev_commit), opt->diffopt.file);
                if (opt->print_parents)
-                       show_parents(commit, abbrev_commit);
+                       show_parents(commit, abbrev_commit, opt->diffopt.file);
                if (opt->children.name)
                        show_children(opt, commit, abbrev_commit);
                show_decorations(opt, commit);
                if (opt->graph && !graph_is_commit_finished(opt->graph)) {
-                       putchar('\n');
+                       putc('\n', opt->diffopt.file);
                        graph_show_remainder(opt->graph);
                }
-               putchar(opt->diffopt.line_termination);
+               putc(opt->diffopt.line_termination, opt->diffopt.file);
                return;
        }
 
@@ -525,7 +587,7 @@ void show_log(struct rev_info *opt)
                if (opt->diffopt.line_termination == '\n' &&
                    !opt->missing_newline)
                        graph_show_padding(opt->graph);
-               putchar(opt->diffopt.line_termination);
+               putc(opt->diffopt.line_termination, opt->diffopt.file);
        }
        opt->shown_one = 1;
 
@@ -539,32 +601,32 @@ void show_log(struct rev_info *opt)
         * Print header line of header..
         */
 
-       if (opt->commit_format == CMIT_FMT_EMAIL) {
+       if (cmit_fmt_is_mail(opt->commit_format)) {
                log_write_email_headers(opt, commit, &ctx.subject, &extra_headers,
                                        &ctx.need_8bit_cte);
        } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
-               fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
+               fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), opt->diffopt.file);
                if (opt->commit_format != CMIT_FMT_ONELINE)
-                       fputs("commit ", stdout);
+                       fputs("commit ", opt->diffopt.file);
 
                if (!opt->graph)
                        put_revision_mark(opt, commit);
-               fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
-                     stdout);
+               fputs(find_unique_abbrev(commit->object.oid.hash, abbrev_commit),
+                     opt->diffopt.file);
                if (opt->print_parents)
-                       show_parents(commit, abbrev_commit);
+                       show_parents(commit, abbrev_commit, opt->diffopt.file);
                if (opt->children.name)
                        show_children(opt, commit, abbrev_commit);
                if (parent)
-                       printf(" (from %s)",
-                              find_unique_abbrev(parent->object.sha1,
+                       fprintf(opt->diffopt.file, " (from %s)",
+                              find_unique_abbrev(parent->object.oid.hash,
                                                  abbrev_commit));
-               fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
+               fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file);
                show_decorations(opt, commit);
                if (opt->commit_format == CMIT_FMT_ONELINE) {
-                       putchar(' ');
+                       putc(' ', opt->diffopt.file);
                } else {
-                       putchar('\n');
+                       putc('\n', opt->diffopt.file);
                        graph_show_oneline(opt->graph);
                }
                if (opt->reflog_info) {
@@ -576,7 +638,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;
@@ -596,7 +658,7 @@ void show_log(struct rev_info *opt)
                struct strbuf notebuf = STRBUF_INIT;
 
                raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
-               format_display_notes(commit->object.sha1, &notebuf,
+               format_display_notes(commit->object.oid.hash, &notebuf,
                                     get_log_output_encoding(), raw);
                ctx.notes_message = notebuf.len
                        ? strbuf_detach(&notebuf, NULL)
@@ -619,9 +681,12 @@ void show_log(struct rev_info *opt)
        ctx.fmt = opt->commit_format;
        ctx.mailmap = opt->mailmap;
        ctx.color = opt->diffopt.use_color;
+       ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
        ctx.output_encoding = get_log_output_encoding();
        if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
                ctx.from_ident = &opt->from_ident;
+       if (opt->graph)
+               ctx.graph_width = graph_width(opt->graph);
        pretty_print_commit(&ctx, commit, &msgbuf);
 
        if (opt->add_signoff)
@@ -629,7 +694,7 @@ void show_log(struct rev_info *opt)
 
        if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
            ctx.notes_message && *ctx.notes_message) {
-               if (ctx.fmt == CMIT_FMT_EMAIL) {
+               if (cmit_fmt_is_mail(ctx.fmt)) {
                        strbuf_addstr(&msgbuf, "---\n");
                        opt->shown_dashes = 1;
                }
@@ -637,7 +702,7 @@ void show_log(struct rev_info *opt)
        }
 
        if (opt->show_log_size) {
-               printf("log size %i\n", (int)msgbuf.len);
+               fprintf(opt->diffopt.file, "log size %i\n", (int)msgbuf.len);
                graph_show_oneline(opt->graph);
        }
 
@@ -650,14 +715,11 @@ void show_log(struct rev_info *opt)
        else
                opt->missing_newline = 0;
 
-       if (opt->graph)
-               graph_show_commit_msg(opt->graph, &msgbuf);
-       else
-               fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
-       if (opt->use_terminator) {
+       graph_show_commit_msg(opt->graph, opt->diffopt.file, &msgbuf);
+       if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) {
                if (!opt->missing_newline)
                        graph_show_padding(opt->graph);
-               putchar(opt->diffopt.line_termination);
+               putc(opt->diffopt.line_termination, opt->diffopt.file);
        }
 
        strbuf_release(&msgbuf);
@@ -681,7 +743,8 @@ int log_tree_diff_flush(struct rev_info *opt)
                show_log(opt);
                if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
                    opt->verbose_header &&
-                   opt->commit_format != CMIT_FMT_ONELINE) {
+                   opt->commit_format != CMIT_FMT_ONELINE &&
+                   !commit_format_is_empty(opt->commit_format)) {
                        /*
                         * When showing a verbose header (i.e. log message),
                         * and not in --pretty=oneline format, we would want
@@ -693,7 +756,7 @@ int log_tree_diff_flush(struct rev_info *opt)
                                struct strbuf *msg = NULL;
                                msg = opt->diffopt.output_prefix(&opt->diffopt,
                                        opt->diffopt.output_prefix_data);
-                               fwrite(msg->buf, msg->len, 1, stdout);
+                               fwrite(msg->buf, msg->len, 1, opt->diffopt.file);
                        }
 
                        /*
@@ -708,8 +771,8 @@ int log_tree_diff_flush(struct rev_info *opt)
                         */
                        if (!opt->shown_dashes &&
                            (pch & opt->diffopt.output_format) == pch)
-                               printf("---");
-                       putchar('\n');
+                               fprintf(opt->diffopt.file, "---");
+                       putc('\n', opt->diffopt.file);
                }
        }
        diff_flush(&opt->diffopt);
@@ -731,19 +794,19 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 {
        int showed_log;
        struct commit_list *parents;
-       unsigned const char *sha1;
+       struct object_id *oid;
 
        if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
                return 0;
 
        parse_commit_or_die(commit);
-       sha1 = commit->tree->object.sha1;
+       oid = &commit->tree->object.oid;
 
        /* Root commit? */
        parents = get_saved_parents(opt, commit);
        if (!parents) {
                if (opt->show_root_diff) {
-                       diff_root_tree_sha1(sha1, "", &opt->diffopt);
+                       diff_root_tree_sha1(oid->hash, "", &opt->diffopt);
                        log_tree_diff_flush(opt);
                }
                return !opt->loginfo;
@@ -762,8 +825,8 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
                         * we merged _in_.
                         */
                        parse_commit_or_die(parents->item);
-                       diff_tree_sha1(parents->item->tree->object.sha1,
-                                      sha1, "", &opt->diffopt);
+                       diff_tree_sha1(parents->item->tree->object.oid.hash,
+                                      oid->hash, "", &opt->diffopt);
                        log_tree_diff_flush(opt);
                        return !opt->loginfo;
                }
@@ -777,8 +840,8 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
                struct commit *parent = parents->item;
 
                parse_commit_or_die(parent);
-               diff_tree_sha1(parent->tree->object.sha1,
-                              sha1, "", &opt->diffopt);
+               diff_tree_sha1(parent->tree->object.oid.hash,
+                              oid->hash, "", &opt->diffopt);
                log_tree_diff_flush(opt);
 
                showed_log |= !opt->loginfo;
@@ -796,17 +859,18 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 int log_tree_commit(struct rev_info *opt, struct commit *commit)
 {
        struct log_info log;
-       int shown;
+       int shown, close_file = opt->diffopt.close_file;
 
        log.commit = commit;
        log.parent = NULL;
        opt->loginfo = &log;
+       opt->diffopt.close_file = 0;
 
        if (opt->line_level_traverse)
                return line_log_print(opt, commit);
 
        if (opt->track_linear && !opt->linear && !opt->reverse_output_stage)
-               printf("\n%s\n", opt->break_bar);
+               fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
        shown = log_tree_diff(opt, commit, &log);
        if (!shown && opt->loginfo && opt->always_show_header) {
                log.parent = NULL;
@@ -814,8 +878,10 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
                shown = 1;
        }
        if (opt->track_linear && !opt->linear && opt->reverse_output_stage)
-               printf("\n%s\n", opt->break_bar);
+               fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
        opt->loginfo = NULL;
-       maybe_flush_or_die(stdout, "stdout");
+       maybe_flush_or_die(opt->diffopt.file, "stdout");
+       if (close_file)
+               fclose(opt->diffopt.file);
        return shown;
 }