Fully detect uninteresting commits.
authorJunio C Hamano <junkio@cox.net>
Thu, 10 Nov 2005 23:47:58 +0000 (15:47 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 11 Nov 2005 18:52:38 +0000 (10:52 -0800)
With the change in the previous round, we are guaranteed to come up
with the list of all relevant merge bases, but sometimes we do not
fully mark unintersting ones due to a horizon effect.  Add a phase to
postprocess, so that we mark all ancestor of "interesting" commit.

This also changes the default ordering of shown commits back to
chronological order, and adds --topo-order flag to show them in
topological order.

Signed-off-by: Junio C Hamano <junkio@cox.net>
show-branch.c

index 714e7f8..631336c 100644 (file)
@@ -199,18 +199,58 @@ static void join_revs(struct commit_list **list_p,
                        parents = parents->next;
                        if ((this_flag & flags) == flags)
                                continue;
-                       parse_commit(p);
+                       if (!p->object.parsed)
+                               parse_commit(p);
                        if (mark_seen(p, seen_p) && !still_interesting)
                                extra--;
                        p->object.flags |= flags;
                        insert_by_date(p, list_p);
                }
        }
+
+       /*
+        * Postprocess to complete well-poisoning.
+        *
+        * At this point we have all the commits we have seen in
+        * seen_p list (which happens to be sorted chronologically but
+        * it does not really matter).  Mark anything that can be
+        * reached from uninteresting commits not interesting.
+        */
+       for (;;) {
+               int changed = 0;
+               struct commit_list *s;
+               for (s = *seen_p; s; s = s->next) {
+                       struct commit *c = s->item;
+                       struct commit_list *parents;
+
+                       if (((c->object.flags & all_revs) != all_revs) &&
+                           !(c->object.flags & UNINTERESTING))
+                               continue;
+
+                       /* The current commit is either a merge base or
+                        * already uninteresting one.  Mark its parents
+                        * as uninteresting commits _only_ if they are
+                        * already parsed.  No reason to find new ones
+                        * here.
+                        */
+                       parents = c->parents;
+                       while (parents) {
+                               struct commit *p = parents->item;
+                               parents = parents->next;
+                               if (!(p->object.flags & UNINTERESTING)) {
+                                       p->object.flags |= UNINTERESTING;
+                                       changed = 1;
+                               }
+                       }
+               }
+               if (!changed)
+                       break;
+       }
 }
 
 static void show_one_commit(struct commit *commit, int no_name)
 {
-       char pretty[128], *cp;
+       char pretty[256], *cp;
        struct commit_name *name = commit->object.util;
        if (commit->object.parsed)
                pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
@@ -360,7 +400,7 @@ int main(int ac, char **av)
        unsigned int rev_mask[MAX_REVS];
        int num_rev, i, extra = 0;
        int all_heads = 0, all_tags = 0;
-       int all_mask, all_revs, shown_merge_point;
+       int all_mask, all_revs;
        char head_path[128];
        const char *head_path_p;
        int head_path_len;
@@ -369,6 +409,8 @@ int main(int ac, char **av)
        int independent = 0;
        int no_name = 0;
        int sha1_name = 0;
+       int shown_merge_point = 0;
+       int topo_order = 0;
 
        setup_git_directory();
 
@@ -394,6 +436,8 @@ int main(int ac, char **av)
                        merge_base = 1;
                else if (!strcmp(arg, "--independent"))
                        independent = 1;
+               else if (!strcmp(arg, "--topo-order"))
+                       topo_order = 1;
                else
                        usage(show_branch_usage);
                ac--; av++;
@@ -496,7 +540,8 @@ int main(int ac, char **av)
                exit(0);
 
        /* Sort topologically */
-       sort_in_topological_order(&seen);
+       if (topo_order)
+               sort_in_topological_order(&seen);
 
        /* Give names to commits */
        if (!sha1_name && !no_name)
@@ -504,15 +549,12 @@ int main(int ac, char **av)
 
        all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
        all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
-       shown_merge_point = 0;
 
        while (seen) {
                struct commit *commit = pop_one_commit(&seen);
                int this_flag = commit->object.flags;
-               int is_merge_point = (this_flag & all_revs) == all_revs;
 
-               if (is_merge_point)
-                       shown_merge_point = 1;
+               shown_merge_point |= ((this_flag & all_revs) == all_revs);
 
                if (1 < num_rev) {
                        for (i = 0; i < num_rev; i++)
@@ -521,9 +563,9 @@ int main(int ac, char **av)
                        putchar(' ');
                }
                show_one_commit(commit, no_name);
-               if (shown_merge_point && is_merge_point)
-                       if (--extra < 0)
-                               break;
+
+               if (shown_merge_point && --extra < 0)
+                       break;
        }
        return 0;
 }