Code

tests: use "git xyzzy" form (t7000 - t7199)
[git.git] / commit.c
index cafed26928cf6ef35fffdd41a8686c32e4fe5ca0..dc0c5bfdab7296bf7febb6f1b1aad64550838c15 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -436,8 +436,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
        /* Mark them and clear the indegree */
        for (next = orig; next; next = next->next) {
                struct commit *commit = next->item;
-               commit->object.flags |= TOPOSORT;
-               commit->indegree = 0;
+               commit->indegree = 1;
        }
 
        /* update the indegree */
@@ -446,7 +445,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
                while (parents) {
                        struct commit *parent = parents->item;
 
-                       if (parent->object.flags & TOPOSORT)
+                       if (parent->indegree)
                                parent->indegree++;
                        parents = parents->next;
                }
@@ -464,7 +463,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
        for (next = orig; next; next = next->next) {
                struct commit *commit = next->item;
 
-               if (!commit->indegree)
+               if (commit->indegree == 1)
                        insert = &commit_list_insert(commit, insert)->next;
        }
 
@@ -486,7 +485,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
                for (parents = commit->parents; parents ; parents = parents->next) {
                        struct commit *parent=parents->item;
 
-                       if (!(parent->object.flags & TOPOSORT))
+                       if (!parent->indegree)
                                continue;
 
                        /*
@@ -494,7 +493,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
                         * when all their children have been emitted thereby
                         * guaranteeing topological order.
                         */
-                       if (!--parent->indegree) {
+                       if (--parent->indegree == 1) {
                                if (!lifo)
                                        insert_by_date(parent, &work);
                                else
@@ -505,7 +504,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
                 * work_item is a commit all of whose children
                 * have already been emitted. we can emit it now.
                 */
-               commit->object.flags &= ~TOPOSORT;
+               commit->indegree = 0;
                *pptr = work_item;
                pptr = &work_item->next;
        }
@@ -725,3 +724,55 @@ int in_merge_bases(struct commit *commit, struct commit **reference, int num)
        free_commit_list(bases);
        return ret;
 }
+
+struct commit_list *reduce_heads(struct commit_list *heads)
+{
+       struct commit_list *p;
+       struct commit_list *result = NULL, **tail = &result;
+       struct commit **other;
+       size_t num_head, num_other;
+
+       if (!heads)
+               return NULL;
+
+       /* Avoid unnecessary reallocations */
+       for (p = heads, num_head = 0; p; p = p->next)
+               num_head++;
+       other = xcalloc(sizeof(*other), num_head);
+
+       /* For each commit, see if it can be reached by others */
+       for (p = heads; p; p = p->next) {
+               struct commit_list *q, *base;
+
+               /* Do we already have this in the result? */
+               for (q = result; q; q = q->next)
+                       if (p->item == q->item)
+                               break;
+               if (q)
+                       continue;
+
+               num_other = 0;
+               for (q = heads; q; q = q->next) {
+                       if (p->item == q->item)
+                               continue;
+                       other[num_other++] = q->item;
+               }
+               if (num_other)
+                       base = get_merge_bases_many(p->item, num_other, other, 1);
+               else
+                       base = NULL;
+               /*
+                * If p->item does not have anything common with other
+                * commits, there won't be any merge base.  If it is
+                * reachable from some of the others, p->item will be
+                * the merge base.  If its history is connected with
+                * others, but p->item is not reachable by others, we
+                * will get something other than p->item back.
+                */
+               if (!base || (base->item != p->item))
+                       tail = &(commit_list_insert(p->item, tail)->next);
+               free_commit_list(base);
+       }
+       free(other);
+       return result;
+}