Merge branch 'lt/logopt'
authorJunio C Hamano <junkio@cox.net>
Tue, 18 Apr 2006 20:56:36 +0000 (13:56 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 18 Apr 2006 20:56:36 +0000 (13:56 -0700)
* lt/logopt:
  Fix "git log --stat": make sure to set recursive with --stat.
  combine-diff: show diffstat with the first parent.
  git.c: LOGSIZE is unused after log printing cleanup.
  Log message printout cleanups (#3): fix --pretty=oneline
  Log message printout cleanups (#2)
  Log message printout cleanups
  rev-list --header: output format fix
  Fixes for option parsing
  log/whatchanged/show - log formatting cleanup.
  Simplify common default options setup for built-in log family.
  Tentative built-in "git show"
  Built-in git-whatchanged.
  rev-list option parser fix.
  Split init_revisions() out of setup_revisions()
  Fix up rev-list option parsing.
  Fix up default abbrev in setup_revisions() argument parser.
  Common option parsing for "git log --diff" and friends

1  2 
combine-diff.c
http-push.c
rev-list.c
revision.c
revision.h

diff --combined combine-diff.c
@@@ -5,6 -5,7 +5,7 @@@
  #include "diffcore.h"
  #include "quote.h"
  #include "xdiff-interface.h"
+ #include "log-tree.h"
  
  static int uninteresting(struct diff_filepair *p)
  {
@@@ -584,12 -585,22 +585,22 @@@ static void reuse_combine_diff(struct s
        sline->p_lno[i] = sline->p_lno[j];
  }
  
+ static void dump_quoted_path(const char *prefix, const char *path)
+ {
+       fputs(prefix, stdout);
+       if (quote_c_style(path, NULL, NULL, 0))
+               quote_c_style(path, NULL, stdout, 0);
+       else
+               printf("%s", path);
+       putchar('\n');
+ }
  static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
-                          int dense, const char *header,
-                          struct diff_options *opt)
+                          int dense, struct rev_info *rev)
  {
+       struct diff_options *opt = &rev->diffopt;
        unsigned long result_size, cnt, lno;
 -      char *result, *cp, *ep;
 +      char *result, *cp;
        struct sline *sline; /* survived lines */
        int mode_differs = 0;
        int i, show_hunks, shown_header = 0;
                cnt++; /* incomplete line */
  
        sline = xcalloc(cnt+2, sizeof(*sline));
 -      ep = result;
        sline[0].bol = result;
        for (lno = 0; lno <= cnt + 1; lno++) {
                sline[lno].lost_tail = &sline[lno].lost_head;
        if (show_hunks || mode_differs || working_tree_file) {
                const char *abb;
  
-               if (header) {
-                       shown_header++;
-                       printf("%s%c", header, opt->line_termination);
-               }
-               printf("diff --%s ", dense ? "cc" : "combined");
-               if (quote_c_style(elem->path, NULL, NULL, 0))
-                       quote_c_style(elem->path, NULL, stdout, 0);
-               else
-                       printf("%s", elem->path);
-               putchar('\n');
+               if (rev->loginfo)
+                       show_log(rev, rev->loginfo, "\n");
+               dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
                printf("index ");
                for (i = 0; i < num_parent; i++) {
                        abb = find_unique_abbrev(elem->parent[i].sha1,
                        }
                        putchar('\n');
                }
+               dump_quoted_path("--- a/", elem->path);
+               dump_quoted_path("+++ b/", elem->path);
                dump_sline(sline, cnt, num_parent);
        }
        free(result);
  
  #define COLONS "::::::::::::::::::::::::::::::::"
  
- static void show_raw_diff(struct combine_diff_path *p, int num_parent, const char *header, struct diff_options *opt)
+ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
  {
 -      int i, offset, mod_type = 'A';
+       struct diff_options *opt = &rev->diffopt;
 +      int i, offset;
        const char *prefix;
        int line_termination, inter_name_termination;
  
        if (!line_termination)
                inter_name_termination = 0;
  
-       if (header)
-               printf("%s%c", header, line_termination);
+       if (rev->loginfo)
+               show_log(rev, rev->loginfo, "\n");
  
 -      for (i = 0; i < num_parent; i++) {
 -              if (p->parent[i].mode)
 -                      mod_type = 'M';
 -      }
 -      if (!p->mode)
 -              mod_type = 'D';
 -
        if (opt->output_format == DIFF_FORMAT_RAW) {
                offset = strlen(COLONS) - num_parent;
                if (offset < 0)
        }
  }
  
int show_combined_diff(struct combine_diff_path *p,
void show_combined_diff(struct combine_diff_path *p,
                       int num_parent,
                       int dense,
-                      const char *header,
-                      struct diff_options *opt)
+                      struct rev_info *rev)
  {
+       struct diff_options *opt = &rev->diffopt;
        if (!p->len)
-               return 0;
+               return;
        switch (opt->output_format) {
        case DIFF_FORMAT_RAW:
        case DIFF_FORMAT_NAME_STATUS:
        case DIFF_FORMAT_NAME:
-               show_raw_diff(p, num_parent, header, opt);
-               return 1;
-       default:
+               show_raw_diff(p, num_parent, rev);
+               return;
        case DIFF_FORMAT_PATCH:
-               return show_patch_diff(p, num_parent, dense, header, opt);
+               show_patch_diff(p, num_parent, dense, rev);
+               return;
+       default:
+               return;
        }
  }
  
- const char *diff_tree_combined_merge(const unsigned char *sha1,
-                            const char *header, int dense,
-                            struct diff_options *opt)
+ void diff_tree_combined_merge(const unsigned char *sha1,
+                            int dense, struct rev_info *rev)
  {
+       struct diff_options *opt = &rev->diffopt;
        struct commit *commit = lookup_commit(sha1);
        struct diff_options diffopts;
        struct commit_list *parents;
        struct combine_diff_path *p, *paths = NULL;
        int num_parent, i, num_paths;
+       int do_diffstat;
  
+       do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
+                      opt->with_stat);
        diffopts = *opt;
-       diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diffopts.with_raw = 0;
+       diffopts.with_stat = 0;
        diffopts.recursive = 1;
  
        /* count parents */
             parents;
             parents = parents->next, i++) {
                struct commit *parent = parents->item;
+               /* show stat against the first parent even
+                * when doing combined diff.
+                */
+               if (i == 0 && do_diffstat)
+                       diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
+               else
+                       diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
                diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
                               &diffopts);
                diffcore_std(&diffopts);
                paths = intersect_paths(paths, i, num_parent);
+               if (do_diffstat && rev->loginfo)
+                       show_log(rev, rev->loginfo,
+                                opt->with_stat ? "---\n" : "\n");
                diff_flush(&diffopts);
+               if (opt->with_stat)
+                       putchar('\n');
        }
  
        /* find out surviving paths */
                        int saved_format = opt->output_format;
                        opt->output_format = DIFF_FORMAT_RAW;
                        for (p = paths; p; p = p->next) {
-                               if (show_combined_diff(p, num_parent, dense,
-                                                      header, opt))
-                                       header = NULL;
+                               show_combined_diff(p, num_parent, dense, rev);
                        }
                        opt->output_format = saved_format;
                        putchar(opt->line_termination);
                }
                for (p = paths; p; p = p->next) {
-                       if (show_combined_diff(p, num_parent, dense,
-                                              header, opt))
-                               header = NULL;
+                       show_combined_diff(p, num_parent, dense, rev);
                }
        }
  
                paths = paths->next;
                free(tmp);
        }
-       return header;
  }
diff --combined http-push.c
@@@ -60,12 -60,12 +60,12 @@@ enum XML_Status 
  #define LOCK_TIME 600
  #define LOCK_REFRESH 30
  
 -/* bits #0-6 in revision.h */
 +/* bits #0-15 in revision.h */
  
 -#define LOCAL    (1u << 7)
 -#define REMOTE   (1u << 8)
 -#define FETCHING (1u << 9)
 -#define PUSHING  (1u << 10)
 +#define LOCAL    (1u<<16)
 +#define REMOTE   (1u<<17)
 +#define FETCHING (1u<<18)
 +#define PUSHING  (1u<<19)
  
  /* We allow "recursive" symbolic refs. Only within reason, though */
  #define MAXDEPTH 5
@@@ -2498,6 -2498,7 +2498,7 @@@ int main(int argc, char **argv
                        commit_argv[3] = old_sha1_hex;
                        commit_argc++;
                }
+               init_revisions(&revs);
                setup_revisions(commit_argc, commit_argv, &revs, NULL);
                free(new_sha1_hex);
                if (old_sha1_hex) {
diff --combined rev-list.c
@@@ -8,9 -8,9 +8,9 @@@
  #include "diff.h"
  #include "revision.h"
  
 -/* bits #0-6 in revision.h */
 +/* bits #0-15 in revision.h */
  
 -#define COUNTED               (1u<<7)
 +#define COUNTED               (1u<<16)
  
  static const char rev_list_usage[] =
  "git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
  struct rev_info revs;
  
  static int bisect_list = 0;
- static int verbose_header = 0;
- static int abbrev = DEFAULT_ABBREV;
- static int abbrev_commit = 0;
  static int show_timestamp = 0;
  static int hdr_termination = 0;
- static const char *commit_prefix = "";
- static enum cmit_fmt commit_format = CMIT_FMT_RAW;
+ static const char *header_prefix;
  
  static void show_commit(struct commit *commit)
  {
        if (show_timestamp)
                printf("%lu ", commit->date);
-       if (commit_prefix[0])
-               fputs(commit_prefix, stdout);
+       if (header_prefix)
+               fputs(header_prefix, stdout);
        if (commit->object.flags & BOUNDARY)
                putchar('-');
-       if (abbrev_commit && abbrev)
-               fputs(find_unique_abbrev(commit->object.sha1, abbrev), stdout);
+       if (revs.abbrev_commit && revs.abbrev)
+               fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
+                     stdout);
        else
                fputs(sha1_to_hex(commit->object.sha1), stdout);
        if (revs.parents) {
                     parents = parents->next)
                        parents->item->object.flags &= ~TMP_MARK;
        }
-       if (commit_format == CMIT_FMT_ONELINE)
+       if (revs.commit_format == CMIT_FMT_ONELINE)
                putchar(' ');
        else
                putchar('\n');
  
-       if (verbose_header) {
+       if (revs.verbose_header) {
                static char pretty_header[16384];
-               pretty_print_commit(commit_format, commit, ~0, pretty_header, sizeof(pretty_header), abbrev);
+               pretty_print_commit(revs.commit_format, commit, ~0,
+                                   pretty_header, sizeof(pretty_header),
+                                   revs.abbrev);
                printf("%s%c", pretty_header, hdr_termination);
        }
        fflush(stdout);
@@@ -297,58 -296,16 +296,16 @@@ int main(int argc, const char **argv
        struct commit_list *list;
        int i;
  
+       init_revisions(&revs);
+       revs.abbrev = 0;
+       revs.commit_format = CMIT_FMT_UNSPECIFIED;
        argc = setup_revisions(argc, argv, &revs, NULL);
  
        for (i = 1 ; i < argc; i++) {
                const char *arg = argv[i];
  
-               /* accept -<digit>, like traditilnal "head" */
-               if ((*arg == '-') && isdigit(arg[1])) {
-                       revs.max_count = atoi(arg + 1);
-                       continue;
-               }
-               if (!strcmp(arg, "-n")) {
-                       if (++i >= argc)
-                               die("-n requires an argument");
-                       revs.max_count = atoi(argv[i]);
-                       continue;
-               }
-               if (!strncmp(arg,"-n",2)) {
-                       revs.max_count = atoi(arg + 2);
-                       continue;
-               }
                if (!strcmp(arg, "--header")) {
-                       verbose_header = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--no-abbrev")) {
-                       abbrev = 0;
-                       continue;
-               }
-               if (!strcmp(arg, "--abbrev")) {
-                       abbrev = DEFAULT_ABBREV;
-                       continue;
-               }
-               if (!strcmp(arg, "--abbrev-commit")) {
-                       abbrev_commit = 1;
-                       continue;
-               }
-               if (!strncmp(arg, "--abbrev=", 9)) {
-                       abbrev = strtoul(arg + 9, NULL, 10);
-                       if (abbrev && abbrev < MINIMUM_ABBREV)
-                               abbrev = MINIMUM_ABBREV;
-                       else if (40 < abbrev)
-                               abbrev = 40;
-                       continue;
-               }
-               if (!strncmp(arg, "--pretty", 8)) {
-                       commit_format = get_commit_format(arg+8);
-                       verbose_header = 1;
-                       hdr_termination = '\n';
-                       if (commit_format == CMIT_FMT_ONELINE)
-                               commit_prefix = "";
-                       else
-                               commit_prefix = "commit ";
+                       revs.verbose_header = 1;
                        continue;
                }
                if (!strcmp(arg, "--timestamp")) {
                usage(rev_list_usage);
  
        }
+       if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
+               /* The command line has a --pretty  */
+               hdr_termination = '\n';
+               if (revs.commit_format == CMIT_FMT_ONELINE)
+                       header_prefix = "";
+               else
+                       header_prefix = "commit ";
+       }
+       else if (revs.verbose_header)
+               /* Only --header was specified */
+               revs.commit_format = CMIT_FMT_RAW;
  
        list = revs.commits;
  
-       if (!list &&
-           (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))
+       if ((!list &&
+            (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
+             !revs.pending_objects)) ||
+           revs.diff)
                usage(rev_list_usage);
  
-       save_commit_buffer = verbose_header;
+       save_commit_buffer = revs.verbose_header;
        track_object_refs = 0;
 +      if (bisect_list)
 +              revs.limited = 1;
  
        prepare_revision_walk(&revs);
        if (revs.tree_objects)
diff --combined revision.c
@@@ -116,21 -116,27 +116,27 @@@ static void add_pending_object(struct r
        add_object(obj, &revs->pending_objects, NULL, name);
  }
  
- static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
+ static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
  {
        struct object *object;
  
        object = parse_object(sha1);
        if (!object)
                die("bad object %s", name);
+       object->flags |= flags;
+       return object;
+ }
+ static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name)
+ {
+       unsigned long flags = object->flags;
  
        /*
         * Tag object? Look what it points to..
         */
        while (object->type == tag_type) {
                struct tag *tag = (struct tag *) object;
-               object->flags |= flags;
-               if (revs->tag_objects && !(object->flags & UNINTERESTING))
+               if (revs->tag_objects && !(flags & UNINTERESTING))
                        add_pending_object(revs, object, tag->tag);
                object = parse_object(tag->tagged->sha1);
                if (!object)
         */
        if (object->type == commit_type) {
                struct commit *commit = (struct commit *)object;
-               object->flags |= flags;
                if (parse_commit(commit) < 0)
                        die("unable to parse commit %s", name);
                if (flags & UNINTERESTING) {
@@@ -241,7 -246,7 +246,7 @@@ int rev_compare_tree(struct rev_info *r
                return REV_TREE_DIFFERENT;
        tree_difference = REV_TREE_SAME;
        if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
-                          &revs->diffopt) < 0)
+                          &revs->pruning) < 0)
                return REV_TREE_DIFFERENT;
        return tree_difference;
  }
@@@ -264,7 -269,7 +269,7 @@@ int rev_same_tree_as_empty(struct rev_i
        empty.size = 0;
  
        tree_difference = 0;
-       retval = diff_tree(&empty, &real, "", &revs->diffopt);
+       retval = diff_tree(&empty, &real, "", &revs->pruning);
        free(tree);
  
        return retval >= 0 && !tree_difference;
@@@ -375,6 -380,9 +380,9 @@@ static void add_parents_to_list(struct 
        if (revs->prune_fn)
                revs->prune_fn(revs, commit);
  
+       if (revs->no_walk)
+               return;
        parent = commit->parents;
        while (parent) {
                struct commit *p = parent->item;
@@@ -451,21 -459,13 +459,13 @@@ static void limit_list(struct rev_info 
        revs->commits = newlist;
  }
  
- static void add_one_commit(struct commit *commit, struct rev_info *revs)
- {
-       if (!commit || (commit->object.flags & SEEN))
-               return;
-       commit->object.flags |= SEEN;
-       commit_list_insert(commit, &revs->commits);
- }
  static int all_flags;
  static struct rev_info *all_revs;
  
  static int handle_one_ref(const char *path, const unsigned char *sha1)
  {
-       struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags);
-       add_one_commit(commit, all_revs);
+       struct object *object = get_reference(all_revs, path, sha1, all_flags);
+       add_pending_object(all_revs, object, "");
        return 0;
  }
  
@@@ -479,9 -479,12 +479,12 @@@ static void handle_all(struct rev_info 
  void init_revisions(struct rev_info *revs)
  {
        memset(revs, 0, sizeof(*revs));
-       revs->diffopt.recursive = 1;
-       revs->diffopt.add_remove = file_add_remove;
-       revs->diffopt.change = file_change;
+       revs->abbrev = DEFAULT_ABBREV;
+       revs->ignore_merges = 1;
+       revs->pruning.recursive = 1;
+       revs->pruning.add_remove = file_add_remove;
+       revs->pruning.change = file_change;
        revs->lifo = 1;
        revs->dense = 1;
        revs->prefix = setup_git_directory();
  
        revs->topo_setter = topo_sort_default_setter;
        revs->topo_getter = topo_sort_default_getter;
+       revs->commit_format = CMIT_FMT_DEFAULT;
+       diff_setup(&revs->diffopt);
  }
  
  /*
@@@ -509,8 -516,6 +516,6 @@@ int setup_revisions(int argc, const cha
        const char **unrecognized = argv + 1;
        int left = 1;
  
-       init_revisions(revs);
        /* First, search for "--" */
        seen_dashdash = 0;
        for (i = 1; i < argc; i++) {
  
        flags = 0;
        for (i = 1; i < argc; i++) {
-               struct commit *commit;
+               struct object *object;
                const char *arg = argv[i];
                unsigned char sha1[20];
                char *dotdot;
                int local_flags;
  
                if (*arg == '-') {
+                       int opts;
                        if (!strncmp(arg, "--max-count=", 12)) {
                                revs->max_count = atoi(arg + 12);
                                continue;
                                revs->unpacked = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "-r")) {
+                               revs->diff = 1;
+                               revs->diffopt.recursive = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "-t")) {
+                               revs->diff = 1;
+                               revs->diffopt.recursive = 1;
+                               revs->diffopt.tree_in_recursive = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "-m")) {
+                               revs->ignore_merges = 0;
+                               continue;
+                       }
+                       if (!strcmp(arg, "-c")) {
+                               revs->diff = 1;
+                               revs->combine_merges = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--cc")) {
+                               revs->diff = 1;
+                               revs->dense_combined_merges = 1;
+                               revs->combine_merges = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "-v")) {
+                               revs->verbose_header = 1;
+                               continue;
+                       }
+                       if (!strncmp(arg, "--pretty", 8)) {
+                               revs->verbose_header = 1;
+                               revs->commit_format = get_commit_format(arg+8);
+                               continue;
+                       }
+                       if (!strcmp(arg, "--root")) {
+                               revs->show_root_diff = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--no-commit-id")) {
+                               revs->no_commit_id = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--always")) {
+                               revs->always_show_header = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--no-abbrev")) {
+                               revs->abbrev = 0;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--abbrev")) {
+                               revs->abbrev = DEFAULT_ABBREV;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--abbrev-commit")) {
+                               revs->abbrev_commit = 1;
+                               continue;
+                       }
+                       if (!strcmp(arg, "--full-diff")) {
+                               revs->diff = 1;
+                               revs->full_diff = 1;
+                               continue;
+                       }
+                       opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
+                       if (opts > 0) {
+                               revs->diff = 1;
+                               i += opts - 1;
+                               continue;
+                       }
                        *unrecognized++ = arg;
                        left++;
                        continue;
                                this = "HEAD";
                        if (!get_sha1(this, from_sha1) &&
                            !get_sha1(next, sha1)) {
-                               struct commit *exclude;
-                               struct commit *include;
+                               struct object *exclude;
+                               struct object *include;
  
-                               exclude = get_commit_reference(revs, this, from_sha1, flags ^ UNINTERESTING);
-                               include = get_commit_reference(revs, next, sha1, flags);
+                               exclude = get_reference(revs, this, from_sha1, flags ^ UNINTERESTING);
+                               include = get_reference(revs, next, sha1, flags);
                                if (!exclude || !include)
                                        die("Invalid revision range %s..%s", arg, next);
-                               add_one_commit(exclude, revs);
-                               add_one_commit(include, revs);
+                               add_pending_object(revs, exclude, this);
+                               add_pending_object(revs, include, next);
                                continue;
                        }
                        *dotdot = '.';
                        revs->prune_data = get_pathspec(revs->prefix, argv + i);
                        break;
                }
-               commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);
-               add_one_commit(commit, revs);
+               object = get_reference(revs, arg, sha1, flags ^ local_flags);
+               add_pending_object(revs, object, arg);
        }
-       if (def && !revs->commits) {
+       if (def && !revs->pending_objects) {
                unsigned char sha1[20];
-               struct commit *commit;
+               struct object *object;
                if (get_sha1(def, sha1) < 0)
                        die("bad default revision '%s'", def);
-               commit = get_commit_reference(revs, def, sha1, 0);
-               add_one_commit(commit, revs);
+               object = get_reference(revs, def, sha1, 0);
+               add_pending_object(revs, object, def);
        }
  
        if (revs->topo_order || revs->unpacked)
                revs->limited = 1;
  
        if (revs->prune_data) {
-               diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
+               diff_tree_setup_paths(revs->prune_data, &revs->pruning);
                revs->prune_fn = try_to_simplify_commit;
+               if (!revs->full_diff)
+                       diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
        }
+       if (revs->combine_merges) {
+               revs->ignore_merges = 0;
+               if (revs->dense_combined_merges)
+                       revs->diffopt.output_format = DIFF_FORMAT_PATCH;
+       }
+       revs->diffopt.abbrev = revs->abbrev;
+       diff_setup_done(&revs->diffopt);
  
        return left;
  }
  
  void prepare_revision_walk(struct rev_info *revs)
  {
-       sort_by_date(&revs->commits);
+       struct object_list *list;
+       list = revs->pending_objects;
+       revs->pending_objects = NULL;
+       while (list) {
+               struct commit *commit = handle_commit(revs, list->item, list->name);
+               if (commit) {
+                       if (!(commit->object.flags & SEEN)) {
+                               commit->object.flags |= SEEN;
+                               insert_by_date(commit, &revs->commits);
+                       }
+               }
+               list = list->next;
+       }
+       if (revs->no_walk)
+               return;
        if (revs->limited)
                limit_list(revs);
        if (revs->topo_order)
@@@ -750,17 -851,6 +851,17 @@@ static void rewrite_parents(struct rev_
        }
  }
  
 +static void mark_boundary_to_show(struct commit *commit)
 +{
 +      struct commit_list *p = commit->parents;
 +      while (p) {
 +              commit = p->item;
 +              p = p->next;
 +              if (commit->object.flags & BOUNDARY)
 +                      commit->object.flags |= BOUNDARY_SHOW;
 +      }
 +}
 +
  struct commit *get_revision(struct rev_info *revs)
  {
        struct commit_list *list = revs->commits;
                }
                if (commit->object.flags & SHOWN)
                        continue;
 -              if (!(commit->object.flags & BOUNDARY) &&
 -                  (commit->object.flags & UNINTERESTING))
 +
 +              /* We want to show boundary commits only when their
 +               * children are shown.  When path-limiter is in effect,
 +               * rewrite_parents() drops some commits from getting shown,
 +               * and there is no point showing boundary parents that
 +               * are not shown.  After rewrite_parents() rewrites the
 +               * parents of a commit that is shown, we mark the boundary
 +               * parents with BOUNDARY_SHOW.
 +               */
 +              if (commit->object.flags & BOUNDARY_SHOW) {
 +                      commit->object.flags |= SHOWN;
 +                      return commit;
 +              }
 +              if (commit->object.flags & UNINTERESTING)
                        continue;
                if (revs->min_age != -1 && (commit->date > revs->min_age))
                        continue;
                        if (revs->parents)
                                rewrite_parents(revs, commit);
                }
 +              if (revs->boundary)
 +                      mark_boundary_to_show(commit);
                commit->object.flags |= SHOWN;
                return commit;
        } while (revs->commits);
diff --combined revision.h
@@@ -7,10 -7,10 +7,11 @@@
  #define SHOWN         (1u<<3)
  #define TMP_MARK      (1u<<4) /* for isolated cases; clean after use */
  #define BOUNDARY      (1u<<5)
 -#define ADDED         (1u<<6) /* Parents already parsed and added? */
 +#define BOUNDARY_SHOW (1u<<6)
 +#define ADDED         (1u<<7) /* Parents already parsed and added? */
  
  struct rev_info;
+ struct log_info;
  
  typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
  
@@@ -27,6 -27,7 +28,7 @@@ struct rev_info 
        /* Traversal flags */
        unsigned int    dense:1,
                        no_merges:1,
+                       no_walk:1,
                        remove_empty_trees:1,
                        lifo:1,
                        topo_order:1,
                        boundary:1,
                        parents:1;
  
+       /* Diff flags */
+       unsigned int    diff:1,
+                       full_diff:1,
+                       show_root_diff:1,
+                       no_commit_id:1,
+                       verbose_header:1,
+                       ignore_merges:1,
+                       combine_merges:1,
+                       dense_combined_merges:1,
+                       always_show_header:1;
+       /* Format info */
+       unsigned int    shown_one:1,
+                       abbrev_commit:1;
+       unsigned int    abbrev;
+       enum cmit_fmt   commit_format;
+       struct log_info *loginfo;
        /* special limits */
        int max_count;
        unsigned long max_age;
        unsigned long min_age;
  
-       /* paths limiting */
+       /* diff info for patches and for paths limiting */
        struct diff_options diffopt;
+       struct diff_options pruning;
  
        topo_sort_set_fn_t topo_setter;
        topo_sort_get_fn_t topo_getter;