static int reachable(struct commit *want) { struct prio_queue work = { compare_commits_by_commit_date }; prio_queue_put(&work, want); while (work.nr) { struct commit_list *list; struct commit *commit = prio_queue_get(&work); if (commit->object.flags & THEY_HAVE) { want->object.flags |= COMMON_KNOWN; break; } if (!commit->object.parsed) parse_object(&commit->object.oid); if (commit->object.flags & REACHABLE) continue; commit->object.flags |= REACHABLE; if (commit->date < oldest_have) continue; for (list = commit->parents; list; list = list->next) { struct commit *parent = list->item; if (!(parent->object.flags & REACHABLE)) prio_queue_put(&work, parent); } } want->object.flags |= REACHABLE; clear_commit_marks(want, REACHABLE); clear_prio_queue(&work); return (want->object.flags & COMMON_KNOWN); }
static const unsigned char *get_rev(void) { struct commit *commit = NULL; while (commit == NULL) { unsigned int mark; struct commit_list *parents; if (rev_list.nr == 0 || non_common_revs == 0) return NULL; commit = prio_queue_get(&rev_list); if (!commit->object.parsed) parse_commit(commit); parents = commit->parents; commit->object.flags |= POPPED; if (!(commit->object.flags & COMMON)) non_common_revs--; if (commit->object.flags & COMMON) { /* do not send "have", and ignore ancestors */ commit = NULL; mark = COMMON | SEEN; } else if (commit->object.flags & COMMON_REF) /* send "have", and ignore ancestors */ mark = COMMON | SEEN; else /* send "have", also for its ancestors */ mark = SEEN; while (parents) { if (!(parents->item->object.flags & SEEN)) rev_list_push(parents->item, mark); if (mark & COMMON) mark_common(parents->item, 1, 0); parents = parents->next; } } return commit->object.sha1; }
/* * 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); } }