@matheusbsbs / matheus-bagliano / commits / 98cf9c3bd7
Fork 0

Introduce reduce_heads()

The new function reduce_heads() is given a list of commits, and removes ones that can be reached from other commits in the list. It is useful for reducing the commits randomly thrown at the git-merge command and remove redundant commits that the user shouldn't have given to it. The implementation uses the get_merge_bases_many() introduced in the previous commit. If the merge base between one commit taken from the list and the remaining commits is the commit itself, that means the commit is reachable from some of the other commits. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jun 27, 2008 at 18:22 UTC 98cf9c3bd7504d36e6049939bf9cc624f2cf5b9f
2 files changed +47
commit.c
+45
@@ -725,3 +725,48 @@ int in_merge_bases(struct commit *commit, struct commit **reference, int num)
725 free_commit_list(bases);
726 return ret;
727 }
728 +
729 +struct commit_list *reduce_heads(struct commit_list *heads)
730 +{
731 + struct commit_list *p;
732 + struct commit_list *result = NULL, **tail = &result;
733 + struct commit **other;
734 + size_t num_head, num_other;
735 +
736 + if (!heads)
737 + return NULL;
738 +
739 + /* Avoid unnecessary reallocations */
740 + for (p = heads, num_head = 0; p; p = p->next)
741 + num_head++;
742 + other = xcalloc(sizeof(*other), num_head);
743 +
744 + /* For each commit, see if it can be reached by others */
745 + for (p = heads; p; p = p->next) {
746 + struct commit_list *q, *base;
747 +
748 + num_other = 0;
749 + for (q = heads; q; q = q->next) {
750 + if (p == q)
751 + continue;
752 + other[num_other++] = q->item;
753 + }
754 + if (num_other) {
755 + base = get_merge_bases_many(p->item, num_other, other, 1);
756 + } else
757 + base = NULL;
758 + /*
759 + * If p->item does not have anything common with other
760 + * commits, there won't be any merge base. If it is
761 + * reachable from some of the others, p->item will be
762 + * the merge base. If its history is connected with
763 + * others, but p->item is not reachable by others, we
764 + * will get something other than p->item back.
765 + */
766 + if (!base || (base->item != p->item))
767 + tail = &(commit_list_insert(p->item, tail)->next);
768 + free_commit_list(base);
769 + }
770 + free(other);
771 + return result;
772 +}
commit.h
+2
@@ -140,4 +140,6 @@ static inline int single_parent(struct commit *commit)
140 return commit->parents && !commit->parents->next;
141 }
142
143 +struct commit_list *reduce_heads(struct commit_list *heads);
144 +
145 #endif /* COMMIT_H */