|
6 | 6 | #define PARENT2 2
|
7 | 7 | #define UNINTERESTING 4
|
8 | 8 |
|
9 |
| -static int interesting(struct commit_list *list) |
| 9 | +static struct commit *interesting(struct commit_list *list) |
10 | 10 | {
|
11 | 11 | while (list) {
|
12 | 12 | struct commit *commit = list->item;
|
13 | 13 | list = list->next;
|
14 | 14 | if (commit->object.flags & UNINTERESTING)
|
15 | 15 | continue;
|
16 |
| - return 1; |
| 16 | + return commit; |
17 | 17 | }
|
18 |
| - return 0; |
| 18 | + return NULL; |
19 | 19 | }
|
20 | 20 |
|
| 21 | +/* |
| 22 | + * A pathological example of how this thing works. |
| 23 | + * |
| 24 | + * Suppose we had this commit graph, where chronologically |
| 25 | + * the timestamp on the commit are A <= B <= C <= D <= E <= F |
| 26 | + * and we are trying to figure out the merge base for E and F |
| 27 | + * commits. |
| 28 | + * |
| 29 | + * F |
| 30 | + * / \ |
| 31 | + * E A D |
| 32 | + * \ / / |
| 33 | + * B / |
| 34 | + * \ / |
| 35 | + * C |
| 36 | + * |
| 37 | + * First we push E and F to list to be processed. E gets bit 1 |
| 38 | + * and F gets bit 2. The list becomes: |
| 39 | + * |
| 40 | + * list=F(2) E(1), result=empty |
| 41 | + * |
| 42 | + * Then we pop F, the newest commit, from the list. Its flag is 2. |
| 43 | + * We scan its parents, mark them reachable from the side that F is |
| 44 | + * reachable from, and push them to the list: |
| 45 | + * |
| 46 | + * list=E(1) D(2) A(2), result=empty |
| 47 | + * |
| 48 | + * Next pop E and do the same. |
| 49 | + * |
| 50 | + * list=D(2) B(1) A(2), result=empty |
| 51 | + * |
| 52 | + * Next pop D and do the same. |
| 53 | + * |
| 54 | + * list=C(2) B(1) A(2), result=empty |
| 55 | + * |
| 56 | + * Next pop C and do the same. |
| 57 | + * |
| 58 | + * list=B(1) A(2), result=empty |
| 59 | + * |
| 60 | + * Now it is B's turn. We mark its parent, C, reachable from B's side, |
| 61 | + * and push it to the list: |
| 62 | + * |
| 63 | + * list=C(3) A(2), result=empty |
| 64 | + * |
| 65 | + * Now pop C and notice it has flags==3. It is placed on the result list, |
| 66 | + * and the list now contains: |
| 67 | + * |
| 68 | + * list=A(2), result=C(3) |
| 69 | + * |
| 70 | + * We pop A and do the same. |
| 71 | + * |
| 72 | + * list=B(3), result=C(3) |
| 73 | + * |
| 74 | + * Next, we pop B and something very interesting happens. It has flags==3 |
| 75 | + * so it is also placed on the result list, and its parents are marked |
| 76 | + * uninteresting, retroactively, and placed back on the list: |
| 77 | + * |
| 78 | + * list=C(7), result=C(7) B(3) |
| 79 | + * |
| 80 | + * Now, list does not have any interesting commit. So we find the newest |
| 81 | + * commit from the result list that is not marked uninteresting. Which is |
| 82 | + * commit B. |
| 83 | + */ |
| 84 | + |
21 | 85 | static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
|
22 | 86 | {
|
23 | 87 | struct commit_list *list = NULL;
|
@@ -58,9 +122,7 @@ static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
|
58 | 122 | insert_by_date(p, &list);
|
59 | 123 | }
|
60 | 124 | }
|
61 |
| - if (!result) |
62 |
| - return NULL; |
63 |
| - return result->item; |
| 125 | + return interesting(result); |
64 | 126 | }
|
65 | 127 |
|
66 | 128 | int main(int argc, char **argv)
|
|
0 commit comments