X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=revision.c;h=d7678cfab4b18082bacee706cb119018b39643a0;hb=5cdeae71ea7330c08cf96b581e2c7696949e3840;hp=48858714250da8e7328c132f60dfcd076d103433;hpb=df45467ec98aa1c532196732c96a62589223353e;p=git.git diff --git a/revision.c b/revision.c index 48858714..d7678cfa 100644 --- a/revision.c +++ b/revision.c @@ -82,18 +82,20 @@ void mark_parents_uninteresting(struct commit *commit) while (parents) { struct commit *commit = parents->item; - 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); + 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 @@ -197,31 +199,27 @@ static int everybody_uninteresting(struct commit_list *orig) return 1; } -#define TREE_SAME 0 -#define TREE_NEW 1 -#define TREE_DIFFERENT 2 -static int tree_difference = TREE_SAME; +static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, const char *base, const char *path) { - int diff = TREE_DIFFERENT; + int diff = REV_TREE_DIFFERENT; /* - * Is it an add of a new file? It means that - * the old tree didn't have it at all, so we - * will turn "TREE_SAME" -> "TREE_NEW", but - * leave any "TREE_DIFFERENT" alone (and if - * it already was "TREE_NEW", we'll keep it - * "TREE_NEW" of course). + * Is it an add of a new file? It means that the old tree + * didn't have it at all, so we will turn "REV_TREE_SAME" -> + * "REV_TREE_NEW", but leave any "REV_TREE_DIFFERENT" alone + * (and if it already was "REV_TREE_NEW", we'll keep it + * "REV_TREE_NEW" of course). */ if (addremove == '+') { diff = tree_difference; - if (diff != TREE_SAME) + if (diff != REV_TREE_SAME) return; - diff = TREE_NEW; + diff = REV_TREE_NEW; } tree_difference = diff; } @@ -232,7 +230,7 @@ static void file_change(struct diff_options *options, const unsigned char *new_sha1, const char *base, const char *path) { - tree_difference = TREE_DIFFERENT; + tree_difference = REV_TREE_DIFFERENT; } static struct diff_options diff_opt = { @@ -241,19 +239,19 @@ static struct diff_options diff_opt = { .change = file_change, }; -static int compare_tree(struct tree *t1, struct tree *t2) +int rev_compare_tree(struct tree *t1, struct tree *t2) { if (!t1) - return TREE_NEW; + return REV_TREE_NEW; if (!t2) - return TREE_DIFFERENT; - tree_difference = TREE_SAME; + return REV_TREE_DIFFERENT; + tree_difference = REV_TREE_SAME; if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0) - return TREE_DIFFERENT; + return REV_TREE_DIFFERENT; return tree_difference; } -static int same_tree_as_empty(struct tree *t1) +int rev_same_tree_as_empty(struct tree *t1) { int retval; void *tree; @@ -280,12 +278,13 @@ static int same_tree_as_empty(struct tree *t1) static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) { struct commit_list **pp, *parent; + int tree_changed = 0; if (!commit->tree) return; if (!commit->parents) { - if (!same_tree_as_empty(commit->tree)) + if (!rev_same_tree_as_empty(commit->tree)) commit->object.flags |= TREECHANGE; return; } @@ -294,31 +293,47 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) while ((parent = *pp) != NULL) { struct commit *p = parent->item; - if (p->object.flags & UNINTERESTING) { - pp = &parent->next; - continue; - } - parse_commit(p); - switch (compare_tree(p->tree, commit->tree)) { - case TREE_SAME: + switch (rev_compare_tree(p->tree, commit->tree)) { + case REV_TREE_SAME: + if (p->object.flags & UNINTERESTING) { + /* Even if a merge with an uninteresting + * side branch brought the entire change + * we are interested in, we do not want + * to lose the other branches of this + * merge, so we just keep going. + */ + pp = &parent->next; + continue; + } parent->next = NULL; commit->parents = parent; return; - case TREE_NEW: - if (revs->remove_empty_trees && same_tree_as_empty(p->tree)) { - *pp = parent->next; - continue; + case REV_TREE_NEW: + if (revs->remove_empty_trees && + rev_same_tree_as_empty(p->tree)) { + /* We are adding all the specified + * paths from this parent, so the + * history beyond this parent is not + * interesting. Remove its parents + * (they are grandparents for us). + * IOW, we pretend this parent is a + * "root" commit. + */ + parse_commit(p); + p->parents = NULL; } /* fallthrough */ - case TREE_DIFFERENT: + case REV_TREE_DIFFERENT: + tree_changed = 1; pp = &parent->next; continue; } die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1)); } - commit->object.flags |= TREECHANGE; + if (tree_changed) + commit->object.flags |= TREECHANGE; } static void add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list) @@ -358,8 +373,8 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st * simplify the commit history and find the parent * that has no differences in the path set if one exists. */ - if (revs->paths) - try_to_simplify_commit(revs, commit); + if (revs->prune_fn) + revs->prune_fn(revs, commit); parent = commit->parents; while (parent) { @@ -381,9 +396,6 @@ static void limit_list(struct rev_info *revs) struct commit_list *newlist = NULL; struct commit_list **p = &newlist; - if (revs->paths) - diff_tree_setup_paths(revs->paths); - while (list) { struct commit_list *entry = list; struct commit *commit = list->item; @@ -435,6 +447,23 @@ static void handle_all(struct rev_info *revs, unsigned flags) for_each_ref(handle_one_ref); } +void init_revisions(struct rev_info *revs) +{ + memset(revs, 0, sizeof(*revs)); + revs->lifo = 1; + revs->dense = 1; + revs->prefix = setup_git_directory(); + revs->max_age = -1; + revs->min_age = -1; + revs->max_count = -1; + + revs->prune_fn = NULL; + revs->prune_data = NULL; + + revs->topo_setter = topo_sort_default_setter; + revs->topo_getter = topo_sort_default_getter; +} + /* * Parse revision information, filling in the "rev_info" structure, * and removing the used arguments from the argument list. @@ -448,13 +477,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch const char **unrecognized = argv + 1; int left = 1; - memset(revs, 0, sizeof(*revs)); - revs->lifo = 1; - revs->dense = 1; - revs->prefix = setup_git_directory(); - revs->max_age = -1; - revs->min_age = -1; - revs->max_count = -1; + init_revisions(revs); /* First, search for "--" */ seen_dashdash = 0; @@ -464,7 +487,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch continue; argv[i] = NULL; argc = i; - revs->paths = get_pathspec(revs->prefix, argv + i + 1); + revs->prune_data = get_pathspec(revs->prefix, argv + i + 1); seen_dashdash = 1; break; } @@ -482,6 +505,21 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->max_count = atoi(arg + 12); continue; } + /* accept -, like traditilnal "head" */ + if ((*arg == '-') && isdigit(arg[1])) { + revs->max_count = atoi(arg + 1); + continue; + } + if (!strcmp(arg, "-n")) { + if (argc <= i + 1) + die("-n requires an argument"); + revs->max_count = atoi(argv[++i]); + continue; + } + if (!strncmp(arg,"-n",2)) { + revs->max_count = atoi(arg + 2); + continue; + } if (!strncmp(arg, "--max-age=", 10)) { revs->max_age = atoi(arg + 10); revs->limited = 1; @@ -549,7 +587,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->remove_empty_trees = 1; continue; } - if (!strncmp(arg, "--no-merges", 11)) { + if (!strcmp(arg, "--no-merges")) { revs->no_merges = 1; continue; } @@ -611,9 +649,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch /* If we didn't have a "--", all filenames must exist */ for (j = i; j < argc; j++) { if (lstat(argv[j], &st) < 0) - die("'%s': %s", arg, strerror(errno)); + die("'%s': %s", argv[j], strerror(errno)); } - revs->paths = get_pathspec(revs->prefix, argv + i); + revs->prune_data = get_pathspec(revs->prefix, argv + i); break; } commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags); @@ -627,8 +665,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch commit = get_commit_reference(revs, def, sha1, 0); add_one_commit(commit, revs); } - if (revs->paths) + + if (revs->prune_data) { + diff_tree_setup_paths(revs->prune_data); + revs->prune_fn = try_to_simplify_commit; revs->limited = 1; + } + return left; } @@ -638,7 +681,9 @@ void prepare_revision_walk(struct rev_info *revs) if (revs->limited) limit_list(revs); if (revs->topo_order) - sort_in_topological_order(&revs->commits, revs->lifo); + sort_in_topological_order_fn(&revs->commits, revs->lifo, + revs->topo_setter, + revs->topo_getter); } static int rewrite_one(struct commit **pp) @@ -669,13 +714,11 @@ static void rewrite_parents(struct commit *commit) struct commit *get_revision(struct rev_info *revs) { struct commit_list *list = revs->commits; - struct commit *commit; if (!list) return NULL; /* Check the max_count ... */ - commit = list->item; switch (revs->max_count) { case -1: break; @@ -686,22 +729,28 @@ struct commit *get_revision(struct rev_info *revs) } do { - commit = pop_most_recent_commit(&revs->commits, SEEN); + struct commit *commit = revs->commits->item; + if (commit->object.flags & (UNINTERESTING|SHOWN)) - continue; + goto next; if (revs->min_age != -1 && (commit->date > revs->min_age)) - continue; + goto next; if (revs->max_age != -1 && (commit->date < revs->max_age)) return NULL; if (revs->no_merges && commit->parents && commit->parents->next) - continue; - if (revs->paths && revs->dense) { + goto next; + if (revs->prune_fn && revs->dense) { if (!(commit->object.flags & TREECHANGE)) - continue; + goto next; rewrite_parents(commit); } + /* More to go? */ + if (revs->max_count) + pop_most_recent_commit(&revs->commits, SEEN); commit->object.flags |= SHOWN; return commit; +next: + pop_most_recent_commit(&revs->commits, SEEN); } while (revs->commits); return NULL; }