commit: use generation numbers for in_merge_bases()
[gitweb.git] / commit.c
index 3e39c86abf885f82ed70cbd5b8212a5436820952..3ecdc1335639783f1a9a262ccf28cb2d500792ad 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -296,6 +296,22 @@ void free_commit_buffer(struct commit *commit)
        }
 }
 
+struct tree *get_commit_tree(const struct commit *commit)
+{
+       if (commit->maybe_tree || !commit->object.parsed)
+               return commit->maybe_tree;
+
+       if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
+               BUG("commit has NULL tree, but was not loaded from commit-graph");
+
+       return get_commit_tree_in_graph(commit);
+}
+
+struct object_id *get_commit_tree_oid(const struct commit *commit)
+{
+       return &get_commit_tree(commit)->object.oid;
+}
+
 const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
 {
        struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
@@ -315,7 +331,7 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
        return ret;
 }
 
-int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph)
 {
        const char *tail = buffer;
        const char *bufptr = buffer;
@@ -335,7 +351,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
                return error("bad tree pointer in commit %s",
                             oid_to_hex(&item->object.oid));
-       item->tree = lookup_tree(&parent);
+       item->maybe_tree = lookup_tree(&parent);
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
@@ -370,6 +386,9 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        }
        item->date = parse_commit_date(bufptr, tail);
 
+       if (check_graph)
+               load_commit_graph_info(item);
+
        return 0;
 }
 
@@ -396,7 +415,7 @@ int parse_commit_gently(struct commit *item, int quiet_on_missing)
                return error("Object %s not a commit",
                             oid_to_hex(&item->object.oid));
        }
-       ret = parse_commit_buffer(item, buffer, size);
+       ret = parse_commit_buffer(item, buffer, size, 0);
        if (save_commit_buffer && !ret) {
                set_commit_buffer(item, buffer, size);
                return 0;
@@ -624,6 +643,24 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,
        return 0;
 }
 
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
+{
+       const struct commit *a = a_, *b = b_;
+
+       /* newer commits first */
+       if (a->generation < b->generation)
+               return 1;
+       else if (a->generation > b->generation)
+               return -1;
+
+       /* use date as a heuristic when generations are equal */
+       if (a->date < b->date)
+               return 1;
+       else if (a->date > b->date)
+               return -1;
+       return 0;
+}
+
 int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
@@ -773,7 +810,7 @@ static int queue_has_nonstale(struct prio_queue *queue)
 /* all input commits in one and twos[] must have been parsed! */
 static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
 {
-       struct prio_queue queue = { compare_commits_by_commit_date };
+       struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
        struct commit_list *result = NULL;
        int i;
 
@@ -1019,12 +1056,19 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
 {
        struct commit_list *bases;
        int ret = 0, i;
+       uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 
        if (parse_commit(commit))
                return ret;
-       for (i = 0; i < nr_reference; i++)
+       for (i = 0; i < nr_reference; i++) {
                if (parse_commit(reference[i]))
                        return ret;
+               if (reference[i]->generation < min_generation)
+                       min_generation = reference[i]->generation;
+       }
+
+       if (commit->generation > min_generation)
+               return ret;
 
        bases = paint_down_to_common(commit, nr_reference, reference);
        if (commit->object.flags & PARENT2)