Make revision limiting more robust against occasional bad commit dates
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Mar 2008 01:56:33 +0000 (18:56 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Mar 2008 08:42:35 +0000 (01:42 -0700)
The revision limiter uses the commit date to decide when it has seen
enough commits to finalize the revision list, but that can get confused
if there are incorrect dates far in the past on some commits.

This makes the logic a bit more robust by

 - we always walk an extra SLOP commits from the source list even if we
   decide that the source list is probably all done (unless the source is
   entirely empty, of course, because then we really can't do anything at
   all)

 - we keep track of the date of the last commit we added to the
   destination list (this will *generally* be the oldest entry we've seen
   so far)

 - we compare that with the youngest entry (the first one) of the source
   list, and if the destination is older than the source, we know we want
   to look at the source.

which causes occasional date mishaps to be handled cleanly.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
revision.c
t/t6009-rev-list-parent.sh

index 63bf2c5c2dd314cfff2f54f76c4f5fd85b3b207e..196fedc9d1297617b74f058f570beb2f5168c3d6 100644 (file)
@@ -564,14 +564,39 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
        free_patch_ids(&ids);
 }
 
-static void add_to_list(struct commit_list **p, struct commit *commit, struct commit_list *n)
+/* How many extra uninteresting commits we want to see.. */
+#define SLOP 5
+
+static int still_interesting(struct commit_list *src, unsigned long date, int slop)
 {
-       p = &commit_list_insert(commit, p)->next;
-       *p = n;
+       /*
+        * No source list at all? We're definitely done..
+        */
+       if (!src)
+               return 0;
+
+       /*
+        * Does the destination list contain entries with a date
+        * before the source list? Definitely _not_ done.
+        */
+       if (date < src->item->date)
+               return SLOP;
+
+       /*
+        * Does the source list still have interesting commits in
+        * it? Definitely not done..
+        */
+       if (!everybody_uninteresting(src))
+               return SLOP;
+
+       /* Ok, we're closing in.. */
+       return slop-1;
 }
 
 static int limit_list(struct rev_info *revs)
 {
+       int slop = SLOP;
+       unsigned long date = ~0ul;
        struct commit_list *list = revs->commits;
        struct commit_list *newlist = NULL;
        struct commit_list **p = &newlist;
@@ -591,16 +616,19 @@ static int limit_list(struct rev_info *revs)
                        return -1;
                if (obj->flags & UNINTERESTING) {
                        mark_parents_uninteresting(commit);
-                       if (everybody_uninteresting(list)) {
-                               if (revs->show_all)
-                                       add_to_list(p, commit, list);
-                               break;
-                       }
-                       if (!revs->show_all)
-                               continue;
+                       if (revs->show_all)
+                               p = &commit_list_insert(commit, p)->next;
+                       slop = still_interesting(list, date, slop);
+                       if (slop)
+                               continue;
+                       /* If showing all, add the whole pending list to the end */
+                       if (revs->show_all)
+                               *p = list;
+                       break;
                }
                if (revs->min_age != -1 && (commit->date > revs->min_age))
                        continue;
+               date = commit->date;
                p = &commit_list_insert(commit, p)->next;
 
                show = show_early_output;
index f248a3293c5d126c60dc525e410e99d5c48a8c04..c8a96a9a994badde602c8bf7a7decda048a00525 100755 (executable)
@@ -27,7 +27,7 @@ test_expect_success setup '
        git log --pretty=oneline --abbrev-commit
 '
 
-test_expect_failure 'one is ancestor of others and should not be shown' '
+test_expect_success 'one is ancestor of others and should not be shown' '
 
        git rev-list one --not four >result &&
        >expect &&