X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=revision.c;h=486393cb0835ce70f685d665b916e1b67974f184;hb=957d6ea78fcbe71481a6f46a58768e100f7908e0;hp=4cf697e2c1fccdf9a6cded983c9d3bbf45fc5af8;hpb=88459358cdd70246e805b0ee7db7fffb9564f80e;p=git.git diff --git a/revision.c b/revision.c index 4cf697e2c..486393cb0 100644 --- a/revision.c +++ b/revision.c @@ -62,8 +62,7 @@ void mark_tree_uninteresting(struct tree *tree) if (parse_tree(tree) < 0) die("bad tree %s", sha1_to_hex(obj->sha1)); - desc.buf = tree->buffer; - desc.size = tree->size; + init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (S_ISDIR(entry.mode)) mark_tree_uninteresting(lookup_tree(entry.sha1)); @@ -116,6 +115,8 @@ void mark_parents_uninteresting(struct commit *commit) void add_pending_object(struct rev_info *revs, struct object *obj, const char *name) { + if (revs->no_walk && (obj->flags & UNINTERESTING)) + die("object ranges do not make sense when not walking revisions"); add_object_array(obj, name, &revs->pending); if (revs->reflog_info && obj->type == OBJ_COMMIT) add_reflog_for_walk(revs->reflog_info, @@ -211,6 +212,13 @@ static int everybody_uninteresting(struct commit_list *orig) return 1; } +/* + * The goal is to get REV_TREE_NEW as the result only if the + * diff consists of all '+' (and no other changes), and + * REV_TREE_DIFFERENT otherwise (of course if the trees are + * the same we want REV_TREE_SAME). That means that once we + * get to REV_TREE_DIFFERENT, we do not have to look any further. + */ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, @@ -234,6 +242,8 @@ static void file_add_remove(struct diff_options *options, diff = REV_TREE_NEW; } tree_difference = diff; + if (tree_difference == REV_TREE_DIFFERENT) + options->has_changes = 1; } static void file_change(struct diff_options *options, @@ -243,6 +253,7 @@ static void file_change(struct diff_options *options, const char *base, const char *path) { tree_difference = REV_TREE_DIFFERENT; + options->has_changes = 1; } int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) @@ -252,6 +263,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) if (!t2) return REV_TREE_DIFFERENT; tree_difference = REV_TREE_SAME; + revs->pruning.has_changes = 0; if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &revs->pruning) < 0) return REV_TREE_DIFFERENT; @@ -262,24 +274,24 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1) { int retval; void *tree; + unsigned long size; struct tree_desc empty, real; if (!t1) return 0; - tree = read_object_with_reference(t1->object.sha1, tree_type, &real.size, NULL); + tree = read_object_with_reference(t1->object.sha1, tree_type, &size, NULL); if (!tree) return 0; - real.buf = tree; - - empty.buf = ""; - empty.size = 0; + init_tree_desc(&real, tree, size); + init_tree_desc(&empty, "", 0); - tree_difference = 0; + tree_difference = REV_TREE_SAME; + revs->pruning.has_changes = 0; retval = diff_tree(&empty, &real, "", &revs->pruning); free(tree); - return retval >= 0 && !tree_difference; + return retval >= 0 && (tree_difference == REV_TREE_SAME); } static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) @@ -348,6 +360,7 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st { struct commit_list *parent = commit->parents; unsigned left_flag; + int add, rest; if (commit->object.flags & ADDED) return; @@ -393,18 +406,19 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st return; left_flag = (commit->object.flags & SYMMETRIC_LEFT); - parent = commit->parents; - while (parent) { + + rest = !revs->first_parent_only; + for (parent = commit->parents, add = 1; parent; add = rest) { struct commit *p = parent->item; parent = parent->next; - parse_commit(p); p->object.flags |= left_flag; if (p->object.flags & SEEN) continue; p->object.flags |= SEEN; - insert_by_date(p, list); + if (add) + insert_by_date(p, list); } } @@ -435,36 +449,6 @@ static void limit_list(struct rev_info *revs) continue; p = &commit_list_insert(commit, p)->next; } - if (revs->boundary) { - /* mark the ones that are on the result list first */ - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - commit->object.flags |= TMP_MARK; - } - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - struct object *obj = &commit->object; - struct commit_list *parent; - if (obj->flags & UNINTERESTING) - continue; - for (parent = commit->parents; - parent; - parent = parent->next) { - struct commit *pcommit = parent->item; - if (!(pcommit->object.flags & UNINTERESTING)) - continue; - pcommit->object.flags |= BOUNDARY; - if (pcommit->object.flags & TMP_MARK) - continue; - pcommit->object.flags |= TMP_MARK; - p = &commit_list_insert(pcommit, p)->next; - } - } - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - commit->object.flags &= ~TMP_MARK; - } - } revs->commits = newlist; } @@ -480,7 +464,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, struct all_refs_cb *cb = cb_data; struct object *object = get_reference(cb->all_revs, path, sha1, cb->all_flags); - add_pending_object(cb->all_revs, object, ""); + add_pending_object(cb->all_revs, object, path); return 0; } @@ -502,7 +486,7 @@ static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data) add_pending_object(cb->all_revs, o, ""); } else if (!cb->warned_bad_reflog) { - warn("reflog of '%s' references pruned commits", + warning("reflog of '%s' references pruned commits", cb->name_for_errormsg); cb->warned_bad_reflog = 1; } @@ -573,6 +557,7 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->ignore_merges = 1; revs->simplify_history = 1; revs->pruning.recursive = 1; + revs->pruning.quiet = 1; revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; revs->lifo = 1; @@ -864,6 +849,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch handle_all(revs, flags); continue; } + if (!strcmp(arg, "--first-parent")) { + revs->first_parent_only = 1; + continue; + } if (!strcmp(arg, "--reflog")) { handle_reflog(revs, flags); continue; @@ -1053,7 +1042,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (!prefixcmp(arg, "--encoding=")) { arg += 11; if (strcmp(arg, "none")) - git_log_output_encoding = strdup(arg); + git_log_output_encoding = xstrdup(arg); else git_log_output_encoding = ""; continue; @@ -1191,17 +1180,6 @@ static void rewrite_parents(struct rev_info *revs, struct commit *commit) } } -static void mark_boundary_to_show(struct commit *commit) -{ - struct commit_list *p = commit->parents; - while (p) { - commit = p->item; - p = p->next; - if (commit->object.flags & BOUNDARY) - commit->object.flags |= BOUNDARY_SHOW; - } -} - static int commit_match(struct commit *commit, struct rev_info *opt) { if (!opt->grep_filter) @@ -1233,15 +1211,9 @@ static struct commit *get_revision_1(struct rev_info *revs) */ if (!revs->limited) { if (revs->max_age != -1 && - (commit->date < revs->max_age)) { - if (revs->boundary) - commit->object.flags |= - BOUNDARY_SHOW | BOUNDARY; - else - continue; - } else - add_parents_to_list(revs, commit, - &revs->commits); + (commit->date < revs->max_age)) + continue; + add_parents_to_list(revs, commit, &revs->commits); } if (commit->object.flags & SHOWN) continue; @@ -1250,18 +1222,6 @@ static struct commit *get_revision_1(struct rev_info *revs) revs->ignore_packed)) continue; - /* We want to show boundary commits only when their - * children are shown. When path-limiter is in effect, - * rewrite_parents() drops some commits from getting shown, - * and there is no point showing boundary parents that - * are not shown. After rewrite_parents() rewrites the - * parents of a commit that is shown, we mark the boundary - * parents with BOUNDARY_SHOW. - */ - if (commit->object.flags & BOUNDARY_SHOW) { - commit->object.flags |= SHOWN; - return commit; - } if (commit->object.flags & UNINTERESTING) continue; if (revs->min_age != -1 && (commit->date > revs->min_age)) @@ -1284,80 +1244,136 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->parents) rewrite_parents(revs, commit); } - if (revs->boundary) - mark_boundary_to_show(commit); - commit->object.flags |= SHOWN; return commit; } while (revs->commits); return NULL; } +static void gc_boundary(struct object_array *array) +{ + unsigned nr = array->nr; + unsigned alloc = array->alloc; + struct object_array_entry *objects = array->objects; + + if (alloc <= nr) { + unsigned i, j; + for (i = j = 0; i < nr; i++) { + if (objects[i].item->flags & SHOWN) + continue; + if (i != j) + objects[j] = objects[i]; + j++; + } + for (i = j; i < nr; i++) + objects[i].item = NULL; + array->nr = j; + } +} + struct commit *get_revision(struct rev_info *revs) { struct commit *c = NULL; + struct commit_list *l; + + if (revs->boundary == 2) { + unsigned i; + struct object_array *array = &revs->boundary_commits; + struct object_array_entry *objects = array->objects; + for (i = 0; i < array->nr; i++) { + c = (struct commit *)(objects[i].item); + if (!c) + continue; + if (!(c->object.flags & CHILD_SHOWN)) + continue; + if (!(c->object.flags & SHOWN)) + break; + } + if (array->nr <= i) + return NULL; - if (revs->reverse) { - struct commit_list *list; + c->object.flags |= SHOWN | BOUNDARY; + return c; + } - /* - * rev_info.reverse is used to note the fact that we - * want to output the list of revisions in reverse - * order. To accomplish this goal, reverse can have - * different values: - * - * 0 do nothing - * 1 reverse the list - * 2 internal use: we have already obtained and - * reversed the list, now we only need to yield - * its items. - */ + if (revs->reverse) { + int limit = -1; - if (revs->reverse == 1) { - revs->reverse = 0; - list = NULL; - while ((c = get_revision(revs))) - commit_list_insert(c, &list); - revs->commits = list; - revs->reverse = 2; + if (0 <= revs->max_count) { + limit = revs->max_count; + if (0 < revs->skip_count) + limit += revs->skip_count; } - - if (!revs->commits) - return NULL; - c = revs->commits->item; - list = revs->commits->next; - free(revs->commits); - revs->commits = list; - return c; + l = NULL; + while ((c = get_revision_1(revs))) { + commit_list_insert(c, &l); + if ((0 < limit) && !--limit) + break; + } + revs->commits = l; + revs->reverse = 0; + revs->max_count = -1; + c = NULL; } - if (0 < revs->skip_count) { - while ((c = get_revision_1(revs)) != NULL) { - if (revs->skip_count-- <= 0) + /* + * Now pick up what they want to give us + */ + c = get_revision_1(revs); + if (c) { + while (0 < revs->skip_count) { + revs->skip_count--; + c = get_revision_1(revs); + if (!c) break; } } - /* Check the max_count ... */ + /* + * Check the max_count. + */ switch (revs->max_count) { case -1: break; case 0: - if (revs->boundary) { - struct commit_list *list = revs->commits; - while (list) { - list->item->object.flags |= - BOUNDARY_SHOW | BOUNDARY; - list = list->next; - } - /* all remaining commits are boundary commits */ - revs->max_count = -1; - revs->limited = 1; - } else - return NULL; + c = NULL; + break; default: revs->max_count--; } + if (c) + c->object.flags |= SHOWN; + + if (!revs->boundary) { return c; - return get_revision_1(revs); + } + + if (!c) { + /* + * get_revision_1() runs out the commits, and + * we are done computing the boundaries. + * switch to boundary commits output mode. + */ + revs->boundary = 2; + return get_revision(revs); + } + + /* + * boundary commits are the commits that are parents of the + * ones we got from get_revision_1() but they themselves are + * not returned from get_revision_1(). Before returning + * 'c', we need to mark its parents that they could be boundaries. + */ + + for (l = c->parents; l; l = l->next) { + struct object *p; + p = &(l->item->object); + if (p->flags & (CHILD_SHOWN | SHOWN)) + continue; + p->flags |= CHILD_SHOWN; + gc_boundary(&revs->boundary_commits); + add_object_array(p, NULL, &revs->boundary_commits); + } + + return c; }