[PATCH] Speed up git-merge-base a lot
[git.git] / merge-base.c
1 #include <stdlib.h>
2 #include "cache.h"
3 #include "commit.h"
4
5 #define PARENT1 1
6 #define PARENT2 2
7 #define UNINTERESTING 4
8
9 static int interesting(struct commit_list *list)
10 {
11         while (list) {
12                 struct commit *commit = list->item;
13                 list = list->next;
14                 if (commit->object.flags & UNINTERESTING)
15                         continue;
16                 return 1;
17         }
18         return 0;
19 }
20
21 static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
22 {
23         struct commit_list *list = NULL;
24         struct commit_list *result = NULL;
25
26         if (rev1 == rev2)
27                 return rev1;
28
29         parse_commit(rev1);
30         parse_commit(rev2);
31
32         rev1->object.flags |= 1;
33         rev2->object.flags |= 2;
34         insert_by_date(rev1, &list);
35         insert_by_date(rev2, &list);
36
37         while (interesting(list)) {
38                 struct commit *commit = list->item;
39                 struct commit_list *tmp = list, *parents;
40                 int flags = commit->object.flags & 7;
41
42                 list = list->next;
43                 free(tmp);
44                 if (flags == 3) {
45                         insert_by_date(commit, &result);
46
47                         /* Mark children of a found merge uninteresting */
48                         flags |= UNINTERESTING;
49                 }
50                 parents = commit->parents;
51                 while (parents) {
52                         struct commit *p = parents->item;
53                         parents = parents->next;
54                         if ((p->object.flags & flags) == flags)
55                                 continue;
56                         parse_commit(p);
57                         p->object.flags |= flags;
58                         insert_by_date(p, &list);
59                 }
60         }
61         if (!result)
62                 return NULL;
63         return result->item;
64 }
65
66 int main(int argc, char **argv)
67 {
68         struct commit *rev1, *rev2, *ret;
69         unsigned char rev1key[20], rev2key[20];
70
71         if (argc != 3 ||
72             get_sha1(argv[1], rev1key) ||
73             get_sha1(argv[2], rev2key)) {
74                 usage("git-merge-base <commit-id> <commit-id>");
75         }
76         rev1 = lookup_commit_reference(rev1key);
77         rev2 = lookup_commit_reference(rev2key);
78         if (!rev1 || !rev2)
79                 return 1;
80         ret = common_ancestor(rev1, rev2);
81         if (!ret)
82                 return 1;
83         printf("%s\n", sha1_to_hex(ret->object.sha1));
84         return 0;
85 }