test: rename $satisfied to $satisfied_prereq
[gitweb.git] / revision.c
index 7444f2eaa13c50afc0fa13b8c43d4f6a08f767fb..9e8f47a25d8def94cbf2a8389039e4d3d670cd06 100644 (file)
@@ -139,11 +139,32 @@ void mark_tree_uninteresting(struct tree *tree)
 
 void mark_parents_uninteresting(struct commit *commit)
 {
-       struct commit_list *parents = commit->parents;
+       struct commit_list *parents = NULL, *l;
+
+       for (l = commit->parents; l; l = l->next)
+               commit_list_insert(l->item, &parents);
 
        while (parents) {
                struct commit *commit = parents->item;
-               if (!(commit->object.flags & UNINTERESTING)) {
+               l = parents;
+               parents = parents->next;
+               free(l);
+
+               while (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;
+
+                       if (commit->object.flags & UNINTERESTING)
+                               break;
+
                        commit->object.flags |= UNINTERESTING;
 
                        /*
@@ -154,21 +175,13 @@ void mark_parents_uninteresting(struct commit *commit)
                         * wasn't uninteresting), in which case we need
                         * to mark its parents recursively too..
                         */
-                       if (commit->parents)
-                               mark_parents_uninteresting(commit);
-               }
+                       if (!commit->parents)
+                               break;
 
-               /*
-                * 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;
+                       for (l = commit->parents->next; l; l = l->next)
+                               commit_list_insert(l->item, &parents);
+                       commit = commit->parents->item;
+               }
        }
 }
 
@@ -416,7 +429,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
        struct commit_list **pp, *parent;
-       int tree_changed = 0, tree_same = 0;
+       int tree_changed = 0, tree_same = 0, nth_parent = 0;
 
        /*
         * If we don't do pruning, everything is interesting
@@ -444,6 +457,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        while ((parent = *pp) != NULL) {
                struct commit *p = parent->item;
 
+               /*
+                * Do not compare with later parents when we care only about
+                * the first parent chain, in order to avoid derailing the
+                * traversal to follow a side branch that brought everything
+                * in the path we are limited to by the pathspec.
+                */
+               if (revs->first_parent_only && nth_parent++)
+                       break;
                if (parse_commit(p) < 0)
                        die("cannot simplify commit %s (because of %s)",
                            sha1_to_hex(commit->object.sha1),
@@ -979,7 +1000,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
                flags ^= UNINTERESTING;
                arg++;
        }
-       if (get_sha1(arg, sha1))
+       if (get_sha1_committish(arg, sha1))
                return 0;
        while (1) {
                it = get_reference(revs, arg, sha1, 0);
@@ -1093,9 +1114,7 @@ static void prepare_show_merge(struct rev_info *revs)
        revs->limited = 1;
 }
 
-int handle_revision_arg(const char *arg_, struct rev_info *revs,
-                       int flags,
-                       int cant_be_filename)
+int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
 {
        struct object_context oc;
        char *dotdot;
@@ -1103,6 +1122,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
        unsigned char sha1[20];
        int local_flags;
        const char *arg = arg_;
+       int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
+       unsigned get_sha1_flags = 0;
 
        dotdot = strstr(arg, "..");
        if (dotdot) {
@@ -1120,8 +1141,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
                        next = "HEAD";
                if (dotdot == arg)
                        this = "HEAD";
-               if (!get_sha1(this, from_sha1) &&
-                   !get_sha1(next, sha1)) {
+               if (!get_sha1_committish(this, from_sha1) &&
+                   !get_sha1_committish(next, sha1)) {
                        struct commit *a, *b;
                        struct commit_list *exclude;
 
@@ -1180,7 +1201,11 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,
                local_flags = UNINTERESTING;
                arg++;
        }
-       if (get_sha1_with_context(arg, 0, sha1, &oc))
+
+       if (revarg_opt & REVARG_COMMITTISH)
+               get_sha1_flags = GET_SHA1_COMMITTISH;
+
+       if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
@@ -1236,7 +1261,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,
                        }
                        die("options not supported in --stdin mode");
                }
-               if (handle_revision_arg(sb.buf, revs, 0, 1))
+               if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", sb.buf);
        }
        if (seen_dashdash)
@@ -1337,11 +1362,13 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->topo_order = 1;
        } else if (!strcmp(arg, "--simplify-merges")) {
                revs->simplify_merges = 1;
+               revs->topo_order = 1;
                revs->rewrite_parents = 1;
                revs->simplify_history = 0;
                revs->limited = 1;
        } else if (!strcmp(arg, "--simplify-by-decoration")) {
                revs->simplify_merges = 1;
+               revs->topo_order = 1;
                revs->rewrite_parents = 1;
                revs->simplify_history = 0;
                revs->simplify_by_decoration = 1;
@@ -1561,6 +1588,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->grep_filter.regflags |= REG_EXTENDED;
        } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
                revs->grep_filter.regflags |= REG_ICASE;
+               DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
        } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
                revs->grep_filter.fixed = 1;
        } else if (!strcmp(arg, "--all-match")) {
@@ -1684,7 +1712,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
  */
 int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
 {
-       int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
+       int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
        struct cmdline_pathspec prune_data;
        const char *submodule = NULL;
 
@@ -1693,21 +1721,28 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                submodule = opt->submodule;
 
        /* First, search for "--" */
-       seen_dashdash = 0;
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (strcmp(arg, "--"))
-                       continue;
-               argv[i] = NULL;
-               argc = i;
-               if (argv[i + 1])
-                       append_prune_data(&prune_data, argv + i + 1);
+       if (opt && opt->assume_dashdash) {
                seen_dashdash = 1;
-               break;
+       } else {
+               seen_dashdash = 0;
+               for (i = 1; i < argc; i++) {
+                       const char *arg = argv[i];
+                       if (strcmp(arg, "--"))
+                               continue;
+                       argv[i] = NULL;
+                       argc = i;
+                       if (argv[i + 1])
+                               append_prune_data(&prune_data, argv + i + 1);
+                       seen_dashdash = 1;
+                       break;
+               }
        }
 
        /* Second, deal with arguments and options */
        flags = 0;
+       revarg_opt = opt ? opt->revarg_opt : 0;
+       if (seen_dashdash)
+               revarg_opt |= REVARG_CANNOT_BE_FILENAME;
        read_from_stdin = 0;
        for (left = i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -1743,7 +1778,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        continue;
                }
 
-               if (handle_revision_arg(arg, revs, flags, seen_dashdash)) {
+
+               if (handle_revision_arg(arg, revs, flags, revarg_opt)) {
                        int j;
                        if (seen_dashdash || *arg == '^')
                                die("bad revision '%s'", arg);
@@ -1755,7 +1791,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                         * but the latter we have checked in the main loop.
                         */
                        for (j = i; j < argc; j++)
-                               verify_filename(revs->prefix, argv[j]);
+                               verify_filename(revs->prefix, argv[j], j == i);
 
                        append_prune_data(&prune_data, argv + i);
                        break;
@@ -1921,8 +1957,9 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
        }
 
        /*
-        * Do we know what commit all of our parents should be rewritten to?
-        * Otherwise we are not ready to rewrite this one yet.
+        * Do we know what commit all of our parents that matter
+        * should be rewritten to?  Otherwise we are not ready to
+        * rewrite this one yet.
         */
        for (cnt = 0, p = commit->parents; p; p = p->next) {
                pst = locate_simplify_state(revs, p->item);
@@ -1930,6 +1967,8 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
                        tail = &commit_list_insert(p->item, tail)->next;
                        cnt++;
                }
+               if (revs->first_parent_only)
+                       break;
        }
        if (cnt) {
                tail = &commit_list_insert(commit, tail)->next;
@@ -1942,8 +1981,13 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
        for (p = commit->parents; p; p = p->next) {
                pst = locate_simplify_state(revs, p->item);
                p->item = pst->simplified;
+               if (revs->first_parent_only)
+                       break;
        }
-       cnt = remove_duplicate_parents(commit);
+       if (!revs->first_parent_only)
+               cnt = remove_duplicate_parents(commit);
+       else
+               cnt = 1;
 
        /*
         * It is possible that we are a merge and one side branch
@@ -1987,25 +2031,31 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
 
 static void simplify_merges(struct rev_info *revs)
 {
-       struct commit_list *list;
+       struct commit_list *list, *next;
        struct commit_list *yet_to_do, **tail;
+       struct commit *commit;
 
-       if (!revs->topo_order)
-               sort_in_topological_order(&revs->commits, revs->lifo);
        if (!revs->prune)
                return;
 
        /* feed the list reversed */
        yet_to_do = NULL;
-       for (list = revs->commits; list; list = list->next)
-               commit_list_insert(list->item, &yet_to_do);
+       for (list = revs->commits; list; list = next) {
+               commit = list->item;
+               next = list->next;
+               /*
+                * Do not free(list) here yet; the original list
+                * is used later in this function.
+                */
+               commit_list_insert(commit, &yet_to_do);
+       }
        while (yet_to_do) {
                list = yet_to_do;
                yet_to_do = NULL;
                tail = &yet_to_do;
                while (list) {
-                       struct commit *commit = list->item;
-                       struct commit_list *next = list->next;
+                       commit = list->item;
+                       next = list->next;
                        free(list);
                        list = next;
                        tail = simplify_one(revs, commit, tail);
@@ -2017,9 +2067,10 @@ static void simplify_merges(struct rev_info *revs)
        revs->commits = NULL;
        tail = &revs->commits;
        while (list) {
-               struct commit *commit = list->item;
-               struct commit_list *next = list->next;
                struct merge_simplify_state *st;
+
+               commit = list->item;
+               next = list->next;
                free(list);
                list = next;
                st = locate_simplify_state(revs, commit);
@@ -2040,10 +2091,16 @@ static void set_children(struct rev_info *revs)
        }
 }
 
+void reset_revision_walk(void)
+{
+       clear_object_flags(SEEN | ADDED | SHOWN);
+}
+
 int prepare_revision_walk(struct rev_info *revs)
 {
        int nr = revs->pending.nr;
        struct object_array_entry *e, *list;
+       struct commit_list **next = &revs->commits;
 
        e = list = revs->pending.objects;
        revs->pending.nr = 0;
@@ -2054,11 +2111,12 @@ int prepare_revision_walk(struct rev_info *revs)
                if (commit) {
                        if (!(commit->object.flags & SEEN)) {
                                commit->object.flags |= SEEN;
-                               commit_list_insert_by_date(commit, &revs->commits);
+                               next = commit_list_append(commit, next);
                        }
                }
                e++;
        }
+       commit_list_sort_by_date(&revs->commits);
        if (!revs->leak_pending)
                free(list);
 
@@ -2128,7 +2186,6 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
        if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
                return 1;
        return grep_buffer(&opt->grep_filter,
-                          NULL, /* we say nothing, not even filename */
                           commit->buffer, strlen(commit->buffer));
 }
 
@@ -2312,29 +2369,28 @@ static struct commit *get_revision_internal(struct rev_info *revs)
        }
 
        /*
-        * Now pick up what they want to give us
+        * If our max_count counter has reached zero, then we are done. We
+        * don't simply return NULL because we still might need to show
+        * boundary commits. But we want to avoid calling get_revision_1, which
+        * might do a considerable amount of work finding the next commit only
+        * for us to throw it away.
+        *
+        * If it is non-zero, then either we don't have a max_count at all
+        * (-1), or it is still counting, in which case we decrement.
         */
-       c = get_revision_1(revs);
-       if (c) {
-               while (0 < revs->skip_count) {
-                       revs->skip_count--;
-                       c = get_revision_1(revs);
-                       if (!c)
-                               break;
+       if (revs->max_count) {
+               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.
-        */
-       switch (revs->max_count) {
-       case -1:
-               break;
-       case 0:
-               c = NULL;
-               break;
-       default:
-               revs->max_count--;
+               if (revs->max_count > 0)
+                       revs->max_count--;
        }
 
        if (c)