+/*
+ * This is a truly stupid algorithm, but it's only
+ * used for bisection, and we just don't care enough.
+ *
+ * We care just barely enough to avoid recursing for
+ * non-merge entries.
+ */
+static int count_distance(struct commit_list *entry)
+{
+ int nr = 0;
+
+ while (entry) {
+ struct commit *commit = entry->item;
+ struct commit_list *p;
+
+ if (commit->object.flags & (UNINTERESTING | COUNTED))
+ break;
+ nr++;
+ commit->object.flags |= COUNTED;
+ p = commit->parents;
+ entry = p;
+ if (p) {
+ p = p->next;
+ while (p) {
+ nr += count_distance(p);
+ p = p->next;
+ }
+ }
+ }
+ return nr;
+}
+
+static void clear_distance(struct commit_list *list)
+{
+ while (list) {
+ struct commit *commit = list->item;
+ commit->object.flags &= ~COUNTED;
+ list = list->next;
+ }
+}
+
+static struct commit_list *find_bisection(struct commit_list *list)
+{
+ int nr, closest;
+ struct commit_list *p, *best;
+
+ nr = 0;
+ p = list;
+ while (p) {
+ nr++;
+ p = p->next;
+ }
+ closest = 0;
+ best = list;
+
+ p = list;
+ while (p) {
+ int distance = count_distance(p);
+ clear_distance(list);
+ if (nr - distance < distance)
+ distance = nr - distance;
+ if (distance > closest) {
+ best = p;
+ closest = distance;
+ }
+ p = p->next;
+ }
+ if (best)
+ best->next = NULL;
+ return best;
+}
+
+static struct commit_list *limit_list(struct commit_list *list)
+{
+ struct commit_list *newlist = NULL;
+ struct commit_list **p = &newlist;
+ while (list) {
+ struct commit *commit = pop_most_recent_commit(&list, SEEN);
+ struct object *obj = &commit->object;
+
+ if (unpacked && has_sha1_pack(obj->sha1))
+ obj->flags |= UNINTERESTING;
+ if (obj->flags & UNINTERESTING) {
+ mark_parents_uninteresting(commit);
+ if (everybody_uninteresting(list))
+ break;
+ continue;
+ }
+ p = &commit_list_insert(commit, p)->next;
+ }
+ if (bisect_list)
+ newlist = find_bisection(newlist);
+ return newlist;
+}
+
+static void add_pending_object(struct object *obj, const char *name)
+{
+ add_object(obj, &pending_objects, name);
+}
+
+static struct commit *get_commit_reference(const char *name, unsigned int flags)
+{
+ unsigned char sha1[20];
+ struct object *object;
+
+ if (get_sha1(name, sha1))
+ usage(rev_list_usage);
+ object = parse_object(sha1);
+ if (!object)
+ die("bad object %s", name);
+
+ /*
+ * Tag object? Look what it points to..
+ */
+ while (object->type == tag_type) {
+ struct tag *tag = (struct tag *) object;
+ object->flags |= flags;
+ if (tag_objects && !(object->flags & UNINTERESTING))
+ add_pending_object(object, tag->tag);
+ object = parse_object(tag->tagged->sha1);
+ }
+
+ /*
+ * Commit object? Just return it, we'll do all the complex
+ * reachability crud.
+ */
+ if (object->type == commit_type) {
+ struct commit *commit = (struct commit *)object;
+ object->flags |= flags;
+ if (parse_commit(commit) < 0)
+ die("unable to parse commit %s", name);
+ if (flags & UNINTERESTING)
+ mark_parents_uninteresting(commit);
+ return commit;
+ }
+
+ /*
+ * Tree object? Either mark it uniniteresting, or add it
+ * to the list of objects to look at later..
+ */
+ if (object->type == tree_type) {
+ struct tree *tree = (struct tree *)object;
+ if (!tree_objects)
+ return NULL;
+ if (flags & UNINTERESTING) {
+ mark_tree_uninteresting(tree);
+ return NULL;
+ }
+ add_pending_object(object, "");
+ return NULL;
+ }
+
+ /*
+ * Blob object? You know the drill by now..
+ */
+ if (object->type == blob_type) {
+ struct blob *blob = (struct blob *)object;
+ if (!blob_objects)
+ return NULL;
+ if (flags & UNINTERESTING) {
+ mark_blob_uninteresting(blob);
+ return NULL;
+ }
+ add_pending_object(object, "");
+ return NULL;
+ }
+ die("%s is unknown object", name);
+}
+