lstat_cache(): print a warning if doing ping-pong between cache types
[gitweb.git] / revision.c
index bcbc7bd7e4257088a8504c12b60ef33d2fac9514..8603c145817488a4ce80111051129d4d715c597b 100644 (file)
@@ -11,6 +11,7 @@
 #include "reflog-walk.h"
 #include "patch-ids.h"
 #include "decorate.h"
+#include "log-tree.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -182,8 +183,11 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
                if (!tag->tagged)
                        die("bad tag");
                object = parse_object(tag->tagged->sha1);
-               if (!object)
+               if (!object) {
+                       if (flags & UNINTERESTING)
+                               return NULL;
                        die("bad object %s", sha1_to_hex(tag->tagged->sha1));
+               }
        }
 
        /*
@@ -199,6 +203,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
                        mark_parents_uninteresting(commit);
                        revs->limited = 1;
                }
+               if (revs->show_source && !commit->util)
+                       commit->util = (void *) name;
                return commit;
        }
 
@@ -292,10 +298,31 @@ static void file_change(struct diff_options *options,
        DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
-static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
+static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct commit *commit)
 {
+       struct tree *t1 = parent->tree;
+       struct tree *t2 = commit->tree;
+
        if (!t1)
                return REV_TREE_NEW;
+
+       if (revs->simplify_by_decoration) {
+               /*
+                * If we are simplifying by decoration, then the commit
+                * is worth showing if it has a tag pointing at it.
+                */
+               if (lookup_decoration(&name_decoration, &commit->object))
+                       return REV_TREE_DIFFERENT;
+               /*
+                * A commit that is not pointed by a tag is uninteresting
+                * if we are not limited by path.  This means that you will
+                * see the usual "commits that touch the paths" plus any
+                * tagged commit by specifying both --simplify-by-decoration
+                * and pathspec.
+                */
+               if (!revs->prune_data)
+                       return REV_TREE_SAME;
+       }
        if (!t2)
                return REV_TREE_DIFFERENT;
        tree_difference = REV_TREE_SAME;
@@ -306,12 +333,13 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree
        return tree_difference;
 }
 
-static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
+static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 {
        int retval;
        void *tree;
        unsigned long size;
        struct tree_desc empty, real;
+       struct tree *t1 = commit->tree;
 
        if (!t1)
                return 0;
@@ -345,7 +373,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                return;
 
        if (!commit->parents) {
-               if (rev_same_tree_as_empty(revs, commit->tree))
+               if (rev_same_tree_as_empty(revs, commit))
                        commit->object.flags |= TREESAME;
                return;
        }
@@ -365,7 +393,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                        die("cannot simplify commit %s (because of %s)",
                            sha1_to_hex(commit->object.sha1),
                            sha1_to_hex(p->object.sha1));
-               switch (rev_compare_tree(revs, p->tree, commit->tree)) {
+               switch (rev_compare_tree(revs, p, commit)) {
                case REV_TREE_SAME:
                        tree_same = 1;
                        if (!revs->simplify_history || (p->object.flags & UNINTERESTING)) {
@@ -385,7 +413,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 
                case REV_TREE_NEW:
                        if (revs->remove_empty_trees &&
-                           rev_same_tree_as_empty(revs, p->tree)) {
+                           rev_same_tree_as_empty(revs, p)) {
                                /* We are adding all the specified
                                 * paths from this parent, so the
                                 * history beyond this parent is not
@@ -454,9 +482,10 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
                while (parent) {
                        struct commit *p = parent->item;
                        parent = parent->next;
+                       if (p)
+                               p->object.flags |= UNINTERESTING;
                        if (parse_commit(p) < 0)
-                               return -1;
-                       p->object.flags |= UNINTERESTING;
+                               continue;
                        if (p->parents)
                                mark_parents_uninteresting(p);
                        if (p->object.flags & SEEN)
@@ -484,6 +513,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
 
                if (parse_commit(p) < 0)
                        return -1;
+               if (revs->show_source && !p->util)
+                       p->util = commit->util;
                p->object.flags |= left_flag;
                if (!(p->object.flags & SEEN)) {
                        p->object.flags |= SEEN;
@@ -953,22 +984,9 @@ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token
        append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what);
 }
 
-static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
+static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern)
 {
-       char *pat;
-       const char *prefix;
-       int patlen, fldlen;
-
-       fldlen = strlen(field);
-       patlen = strlen(pattern);
-       pat = xmalloc(patlen + fldlen + 10);
-       prefix = ".*";
-       if (*pattern == '^') {
-               prefix = "";
-               pattern++;
-       }
-       sprintf(pat, "^%s %s%s", field, prefix, pattern);
-       add_grep(revs, pat, GREP_PATTERN_HEAD);
+       append_header_grep_pattern(&revs->grep_filter, field, pattern);
 }
 
 static void add_message_grep(struct rev_info *revs, const char *pattern)
@@ -981,7 +999,7 @@ static void add_ignore_packed(struct rev_info *revs, const char *name)
        int num = ++revs->num_ignore_packed;
 
        revs->ignore_packed = xrealloc(revs->ignore_packed,
-                                      sizeof(const char **) * (num + 1));
+                                      sizeof(const char *) * (num + 1));
        revs->ignore_packed[num-1] = name;
        revs->ignore_packed[num] = NULL;
 }
@@ -1046,6 +1064,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->rewrite_parents = 1;
                revs->simplify_history = 0;
                revs->limited = 1;
+       } else if (!strcmp(arg, "--simplify-by-decoration")) {
+               revs->simplify_merges = 1;
+               revs->rewrite_parents = 1;
+               revs->simplify_history = 0;
+               revs->simplify_by_decoration = 1;
+               revs->limited = 1;
+               revs->prune = 1;
+               load_ref_decorations();
        } else if (!strcmp(arg, "--date-order")) {
                revs->lifo = 0;
                revs->topo_order = 1;
@@ -1159,9 +1185,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
         * Grepping the commit log
         */
        else if (!prefixcmp(arg, "--author=")) {
-               add_header_grep(revs, "author", arg+9);
+               add_header_grep(revs, GREP_HEADER_AUTHOR, arg+9);
        } else if (!prefixcmp(arg, "--committer=")) {
-               add_header_grep(revs, "committer", arg+12);
+               add_header_grep(revs, GREP_HEADER_COMMITTER, arg+12);
        } else if (!prefixcmp(arg, "--grep=")) {
                add_message_grep(revs, arg+7);
        } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
@@ -1241,6 +1267,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 
                        if (!strcmp(arg, "--all")) {
                                handle_refs(revs, flags, for_each_ref);
+                               handle_refs(revs, flags, head_ref);
                                continue;
                        }
                        if (!strcmp(arg, "--branches")) {
@@ -1806,26 +1833,6 @@ static struct commit *get_revision_internal(struct rev_info *revs)
                return c;
        }
 
-       if (revs->reverse) {
-               int limit = -1;
-
-               if (0 <= revs->max_count) {
-                       limit = revs->max_count;
-                       if (0 < revs->skip_count)
-                               limit += revs->skip_count;
-               }
-               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;
-       }
-
        /*
         * Now pick up what they want to give us
         */
@@ -1898,7 +1905,23 @@ static struct commit *get_revision_internal(struct rev_info *revs)
 
 struct commit *get_revision(struct rev_info *revs)
 {
-       struct commit *c = get_revision_internal(revs);
+       struct commit *c;
+       struct commit_list *reversed;
+
+       if (revs->reverse) {
+               reversed = NULL;
+               while ((c = get_revision_internal(revs))) {
+                       commit_list_insert(c, &reversed);
+               }
+               revs->commits = reversed;
+               revs->reverse = 0;
+               revs->reverse_output_stage = 1;
+       }
+
+       if (revs->reverse_output_stage)
+               return pop_commit(&revs->commits);
+
+       c = get_revision_internal(revs);
        if (c && revs->graph)
                graph_update(revs->graph, c);
        return c;