Code

Merge git://git.kernel.org/pub/scm/gitk/gitk
[git.git] / builtin-log.c
index 71ae55b9eb661965ee19e7ce9701f0526cbf7b4d..d983cbc7bc98f1b28332c18946e5111a6dcba9ab 100644 (file)
@@ -5,6 +5,7 @@
  *              2006 Junio Hamano
  */
 #include "cache.h"
+#include "color.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
 #include "patch-ids.h"
 #include "refs.h"
 #include "run-command.h"
+#include "shortlog.h"
 
 static int default_show_root = 1;
 static const char *fmt_patch_subject_prefix = "PATCH";
+static const char *fmt_pretty;
 
 static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
 {
@@ -52,6 +55,8 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
+       if (fmt_pretty)
+               rev->commit_format = get_commit_format(fmt_pretty);
        rev->verbose_header = 1;
        DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
        rev->show_root_diff = default_show_root;
@@ -198,7 +203,8 @@ static int cmd_log_walk(struct rev_info *rev)
        if (rev->early_output)
                setup_early_output(rev);
 
-       prepare_revision_walk(rev);
+       if (prepare_revision_walk(rev))
+               die("revision walk setup failed");
 
        if (rev->early_output)
                finish_early_output(rev);
@@ -218,6 +224,8 @@ static int cmd_log_walk(struct rev_info *rev)
 
 static int git_log_config(const char *var, const char *value)
 {
+       if (!strcmp(var, "format.pretty"))
+               return git_config_string(&fmt_pretty, var, value);
        if (!strcmp(var, "format.subjectprefix")) {
                if (!value)
                        config_error_nonbool(var);
@@ -236,6 +244,10 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
 
        git_config(git_log_config);
+
+       if (diff_use_color_default == -1)
+               diff_use_color_default = git_use_color_default;
+
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.simplify_history = 0;
@@ -308,6 +320,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
        int i, count, ret = 0;
 
        git_config(git_log_config);
+
+       if (diff_use_color_default == -1)
+               diff_use_color_default = git_use_color_default;
+
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.combine_merges = 1;
@@ -368,6 +384,10 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
 
        git_config(git_log_config);
+
+       if (diff_use_color_default == -1)
+               diff_use_color_default = git_use_color_default;
+
        init_revisions(&rev, prefix);
        init_reflog_walk(&rev.reflog_info);
        rev.abbrev_commit = 1;
@@ -396,6 +416,10 @@ int cmd_log(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
 
        git_config(git_log_config);
+
+       if (diff_use_color_default == -1)
+               diff_use_color_default = git_use_color_default;
+
        init_revisions(&rev, prefix);
        rev.always_show_header = 1;
        cmd_log_init(argc, argv, prefix, &rev);
@@ -587,7 +611,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
        o2->flags ^= UNINTERESTING;
        add_pending_object(&check_rev, o1, "o1");
        add_pending_object(&check_rev, o2, "o2");
-       prepare_revision_walk(&check_rev);
+       if (prepare_revision_walk(&check_rev))
+               die("revision walk setup failed");
 
        while ((commit = get_revision(&check_rev)) != NULL) {
                /* ignore merges */
@@ -621,19 +646,22 @@ static void gen_message_id(struct rev_info *info, char *base)
        info->message_id = strbuf_detach(&buf, NULL);
 }
 
-static void make_cover_letter(struct rev_info *rev,
-               int use_stdout, int numbered, int numbered_files,
-                             struct commit *origin, struct commit *head)
+static void make_cover_letter(struct rev_info *rev, int use_stdout,
+                             int numbered, int numbered_files,
+                             struct commit *origin,
+                             int nr, struct commit **list, struct commit *head)
 {
        const char *committer;
-       const char *origin_sha1, *head_sha1;
-       const char *argv[7];
+       char *head_sha1;
        const char *subject_start = NULL;
        const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
        const char *msg;
        const char *extra_headers = rev->extra_headers;
+       struct shortlog log;
        struct strbuf sb;
+       int i;
        const char *encoding = "utf-8";
+       struct diff_options opts;
 
        if (rev->commit_format != CMIT_FMT_EMAIL)
                die("Cover letter needs email format");
@@ -642,7 +670,6 @@ static void make_cover_letter(struct rev_info *rev,
                                NULL : "cover-letter", 0, rev->total))
                return;
 
-       origin_sha1 = sha1_to_hex(origin ? origin->object.sha1 : null_sha1);
        head_sha1 = sha1_to_hex(head->object.sha1);
 
        log_write_email_headers(rev, head_sha1, &subject_start, &extra_headers);
@@ -660,34 +687,33 @@ static void make_cover_letter(struct rev_info *rev,
 
        strbuf_release(&sb);
 
+       shortlog_init(&log);
+       log.wrap_lines = 1;
+       log.wrap = 72;
+       log.in1 = 2;
+       log.in2 = 4;
+       for (i = 0; i < nr; i++)
+               shortlog_add_commit(&log, list[i]);
+
+       shortlog_output(&log);
+
        /*
-        * We can only do diffstat with a unique reference point, and
-        * log is a bit tricky, so just skip it.
+        * We can only do diffstat with a unique reference point
         */
        if (!origin)
                return;
 
-       argv[0] = "shortlog";
-       argv[1] = head_sha1;
-       argv[2] = "--not";
-       argv[3] = origin_sha1;
-       argv[4] = "--";
-       argv[5] = NULL;
-       fflush(stdout);
-       run_command_v_opt(argv, RUN_GIT_CMD);
-
-       argv[0] = "diff";
-       argv[1] = "--stat";
-       argv[2] = "--summary";
-       argv[3] = head_sha1;
-       argv[4] = "--not";
-       argv[5] = origin_sha1;
-       argv[6] = "--";
-       argv[7] = NULL;
-       fflush(stdout);
-       run_command_v_opt(argv, RUN_GIT_CMD);
-
-       fflush(stdout);
+       memcpy(&opts, &rev->diffopt, sizeof(opts));
+       opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+
+       diff_setup_done(&opts);
+
+       diff_tree_sha1(origin->tree->object.sha1,
+                      head->tree->object.sha1,
+                      "", &opts);
+       diffcore_std(&opts);
+       diff_flush(&opts);
+
        printf("\n");
 }
 
@@ -727,6 +753,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int ignore_if_in_upstream = 0;
        int thread = 0;
        int cover_letter = 0;
+       int boundary_count = 0;
        struct commit *origin = NULL, *head = NULL;
        const char *in_reply_to = NULL;
        struct patch_ids ids;
@@ -771,6 +798,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                                die("Need a number for --start-number");
                        start_number = strtol(argv[i], NULL, 10);
                }
+               else if (!prefixcmp(argv[i], "--cc=")) {
+                       ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc);
+                       extra_cc[extra_cc_nr++] = xstrdup(argv[i] + 5);
+               }
                else if (!strcmp(argv[i], "-k") ||
                                !strcmp(argv[i], "--keep-subject")) {
                        keep_subject = 1;
@@ -913,19 +944,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        }
        if (cover_letter) {
                /* remember the range */
-               int negative_count = 0;
                int i;
                for (i = 0; i < rev.pending.nr; i++) {
                        struct object *o = rev.pending.objects[i].item;
-                       if (o->flags & UNINTERESTING) {
-                               origin = (struct commit *)o;
-                               negative_count++;
-                       } else
+                       if (!(o->flags & UNINTERESTING))
                                head = (struct commit *)o;
                }
-               /* Multiple origins don't work for diffstat. */
-               if (negative_count > 1)
-                       origin = NULL;
                /* We can't generate a cover letter without any patches */
                if (!head)
                        return 0;
@@ -937,8 +961,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        if (!use_stdout)
                realstdout = xfdopen(xdup(1), "w");
 
-       prepare_revision_walk(&rev);
+       if (prepare_revision_walk(&rev))
+               die("revision walk setup failed");
+       rev.boundary = 1;
        while ((commit = get_revision(&rev)) != NULL) {
+               if (commit->object.flags & BOUNDARY) {
+                       boundary_count++;
+                       origin = (boundary_count == 1) ? commit : NULL;
+                       continue;
+               }
+
                /* ignore merges */
                if (commit->parents && commit->parents->next)
                        continue;
@@ -962,7 +994,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout, numbered, numbered_files,
-                                 origin, head);
+                                 origin, nr, list, head);
                total++;
                start_number--;
        }
@@ -1092,7 +1124,8 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                die("Unknown commit %s", limit);
 
        /* reverse the list of commits */
-       prepare_revision_walk(&revs);
+       if (prepare_revision_walk(&revs))
+               die("revision walk setup failed");
        while ((commit = get_revision(&revs)) != NULL) {
                /* ignore merges */
                if (commit->parents && commit->parents->next)