void mark_parents_uninteresting(struct commit *commit) { struct commit_list *parents = commit->parents; while (parents) { struct commit *commit = parents->item; if (!(commit->object.flags & UNINTERESTING)) { commit->object.flags |= UNINTERESTING; /* * Normally we haven't parsed the parent * yet, so we won't have a parent of a parent * here. However, it may turn out that we've * reached this commit some other way (where it * wasn't uninteresting), in which case we need * to mark its parents recursively too.. */ if (commit->parents) mark_parents_uninteresting(commit); } /* * A missing commit is ok iff its parent is marked * uninteresting. * * We just mark such a thing parsed, so that when * it is popped next time around, we won't be trying * to parse it and get an error. */ if (!has_sha1_file(commit->object.sha1)) commit->object.parsed = 1; parents = parents->next; } }
static int limit_list(struct rev_info *revs) { int slop = SLOP; unsigned long date = ~0ul; struct commit_list *list = revs->commits; struct commit_list *newlist = NULL; struct commit_list **p = &newlist; while (list) { struct commit_list *entry = list; struct commit *commit = list->item; struct object *obj = &commit->object; show_early_output_fn_t show; list = list->next; free(entry); if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; if (add_parents_to_list(revs, commit, &list, NULL) < 0) return -1; if (obj->flags & UNINTERESTING) { mark_parents_uninteresting(commit); if (revs->show_all) p = &commit_list_insert(commit, p)->next; slop = still_interesting(list, date, slop); if (slop) continue; /* If showing all, add the whole pending list to the end */ if (revs->show_all) *p = list; break; } if (revs->min_age != -1 && (commit->date > revs->min_age)) continue; date = commit->date; p = &commit_list_insert(commit, p)->next; show = show_early_output; if (!show) continue; show(revs, newlist); show_early_output = NULL; } if (revs->cherry_pick) cherry_pick_list(newlist, revs); revs->commits = newlist; return 0; }
static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name) { unsigned long flags = object->flags; /* * Tag object? Look what it points to.. */ while (object->type == OBJ_TAG) { struct tag *tag = (struct tag *) object; if (revs->tag_objects && !(flags & UNINTERESTING)) add_pending_object(revs, object, tag->tag); if (!tag->tagged) die("bad tag"); object = parse_object(tag->tagged->sha1); if (!object) die("bad object %s", sha1_to_hex(tag->tagged->sha1)); } /* * Commit object? Just return it, we'll do all the complex * reachability crud. */ if (object->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)object; if (parse_commit(commit) < 0) die("unable to parse commit %s", name); if (flags & UNINTERESTING) { commit->object.flags |= UNINTERESTING; mark_parents_uninteresting(commit); revs->limited = 1; } return commit; } /* * Tree object? Either mark it uniniteresting, or add it * to the list of objects to look at later.. */ if (object->type == OBJ_TREE) { struct tree *tree = (struct tree *)object; if (!revs->tree_objects) return NULL; if (flags & UNINTERESTING) { mark_tree_uninteresting(tree); return NULL; } add_pending_object(revs, object, ""); return NULL; } /* * Blob object? You know the drill by now.. */ if (object->type == OBJ_BLOB) { struct blob *blob = (struct blob *)object; if (!revs->blob_objects) return NULL; if (flags & UNINTERESTING) { mark_blob_uninteresting(blob); return NULL; } add_pending_object(revs, object, ""); return NULL; } die("%s is unknown object", name); }
static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list, struct commit_list **cache_ptr) { struct commit_list *parent = commit->parents; unsigned left_flag; struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL; if (commit->object.flags & ADDED) return 0; commit->object.flags |= ADDED; /* * If the commit is uninteresting, don't try to * prune parents - we want the maximal uninteresting * set. * * Normally we haven't parsed the parent * yet, so we won't have a parent of a parent * here. However, it may turn out that we've * reached this commit some other way (where it * wasn't uninteresting), in which case we need * to mark its parents recursively too.. */ if (commit->object.flags & UNINTERESTING) { while (parent) { struct commit *p = parent->item; parent = parent->next; if (parse_commit(p) < 0) return -1; p->object.flags |= UNINTERESTING; if (p->parents) mark_parents_uninteresting(p); if (p->object.flags & SEEN) continue; p->object.flags |= SEEN; insert_by_date_cached(p, list, cached_base, cache_ptr); } return 0; } /* * Ok, the commit wasn't uninteresting. Try to * simplify the commit history and find the parent * that has no differences in the path set if one exists. */ try_to_simplify_commit(revs, commit); if (revs->no_walk) return 0; left_flag = (commit->object.flags & SYMMETRIC_LEFT); for (parent = commit->parents; parent; parent = parent->next) { struct commit *p = parent->item; if (parse_commit(p) < 0) return -1; p->object.flags |= left_flag; if (!(p->object.flags & SEEN)) { p->object.flags |= SEEN; insert_by_date_cached(p, list, cached_base, cache_ptr); } if (revs->first_parent_only) break; } return 0; }
/* * The main loop -- while we have blobs with lines whose true origin * is still unknown, pick one blob, and allow its lines to pass blames * to its parents. */ void assign_blame(struct blame_scoreboard *sb, int opt) { struct rev_info *revs = sb->revs; struct commit *commit = prio_queue_get(&sb->commits); while (commit) { struct blame_entry *ent; struct blame_origin *suspect = commit->util; /* find one suspect to break down */ while (suspect && !suspect->suspects) suspect = suspect->next; if (!suspect) { commit = prio_queue_get(&sb->commits); continue; } assert(commit == suspect->commit); /* * We will use this suspect later in the loop, * so hold onto it in the meantime. */ blame_origin_incref(suspect); parse_commit(commit); if (sb->reverse || (!(commit->object.flags & UNINTERESTING) && !(revs->max_age != -1 && commit->date < revs->max_age))) pass_blame(sb, suspect, opt); else { commit->object.flags |= UNINTERESTING; if (commit->object.parsed) mark_parents_uninteresting(commit); } /* treat root commit as boundary */ if (!commit->parents && !sb->show_root) commit->object.flags |= UNINTERESTING; /* Take responsibility for the remaining entries */ ent = suspect->suspects; if (ent) { suspect->guilty = 1; for (;;) { struct blame_entry *next = ent->next; if (sb->found_guilty_entry) sb->found_guilty_entry(ent, sb->found_guilty_entry_data); if (next) { ent = next; continue; } ent->next = sb->ent; sb->ent = suspect->suspects; suspect->suspects = NULL; break; } } blame_origin_decref(suspect); if (sb->debug) /* sanity */ sanity_check_refcnt(sb); } }