18d81d08a5147acd09b6f1e2f57f647ea5bf1fc5
   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
   9static 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
  21static 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
  66int 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}