Add "--show-all" revision walker flag for debugging
[gitweb.git] / revision.c
index e76da0d448f81d8b6b496990bc2568fef3662671..76faf4b0094f6da1c3cd1f7b3e03b5a2fed29cee 100644 (file)
@@ -10,6 +10,8 @@
 #include "reflog-walk.h"
 #include "patch-ids.h"
 
+volatile show_early_output_fn_t show_early_output;
+
 static char *path_name(struct name_path *path, const char *name)
 {
        struct name_path *p;
@@ -65,10 +67,17 @@ void mark_tree_uninteresting(struct tree *tree)
 
        init_tree_desc(&desc, tree->buffer, tree->size);
        while (tree_entry(&desc, &entry)) {
-               if (S_ISDIR(entry.mode))
+               switch (object_type(entry.mode)) {
+               case OBJ_TREE:
                        mark_tree_uninteresting(lookup_tree(entry.sha1));
-               else
+                       break;
+               case OBJ_BLOB:
                        mark_blob_uninteresting(lookup_blob(entry.sha1));
+                       break;
+               default:
+                       /* Subproject commit - not in this repository */
+                       break;
+               }
        }
 
        /*
@@ -130,6 +139,18 @@ void add_pending_object(struct rev_info *revs, struct object *obj, const char *n
        add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
 }
 
+void add_head_to_pending(struct rev_info *revs)
+{
+       unsigned char sha1[20];
+       struct object *obj;
+       if (get_sha1("HEAD", sha1))
+               return;
+       obj = parse_object(sha1);
+       if (!obj)
+               return;
+       add_pending_object(revs, obj, "HEAD");
+}
+
 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
 {
        struct object *object;
@@ -250,7 +271,7 @@ static void file_add_remove(struct diff_options *options,
        }
        tree_difference = diff;
        if (tree_difference == REV_TREE_DIFFERENT)
-               options->has_changes = 1;
+               DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 static void file_change(struct diff_options *options,
@@ -260,7 +281,7 @@ static void file_change(struct diff_options *options,
                 const char *base, const char *path)
 {
        tree_difference = REV_TREE_DIFFERENT;
-       options->has_changes = 1;
+       DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
@@ -270,7 +291,7 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree
        if (!t2)
                return REV_TREE_DIFFERENT;
        tree_difference = REV_TREE_SAME;
-       revs->pruning.has_changes = 0;
+       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
        if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
                           &revs->pruning) < 0)
                return REV_TREE_DIFFERENT;
@@ -294,7 +315,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
        init_tree_desc(&empty, "", 0);
 
        tree_difference = REV_TREE_SAME;
-       revs->pruning.has_changes = 0;
+       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
        retval = diff_tree(&empty, &real, "", &revs->pruning);
        free(tree);
 
@@ -306,15 +327,28 @@ 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;
 
+       /*
+        * If we don't do pruning, everything is interesting
+        */
+       if (!revs->prune)
+               return;
+
        if (!commit->tree)
                return;
 
        if (!commit->parents) {
-               if (!rev_same_tree_as_empty(revs, commit->tree))
-                       commit->object.flags |= TREECHANGE;
+               if (rev_same_tree_as_empty(revs, commit->tree))
+                       commit->object.flags |= TREESAME;
                return;
        }
 
+       /*
+        * Normal non-merge commit? If we don't want to make the
+        * history dense, we consider it always to be a change..
+        */
+       if (!revs->dense && !commit->parents->next)
+               return;
+
        pp = &commit->parents;
        while ((parent = *pp) != NULL) {
                struct commit *p = parent->item;
@@ -338,6 +372,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                        }
                        parent->next = NULL;
                        commit->parents = parent;
+                       commit->object.flags |= TREESAME;
                        return;
 
                case REV_TREE_NEW:
@@ -366,7 +401,8 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
        }
        if (tree_changed && !tree_same)
-               commit->object.flags |= TREECHANGE;
+               return;
+       commit->object.flags |= TREESAME;
 }
 
 static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
@@ -413,8 +449,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
         * simplify the commit history and find the parent
         * that has no differences in the path set if one exists.
         */
-       if (revs->prune_fn)
-               revs->prune_fn(revs, commit);
+       try_to_simplify_commit(revs, commit);
 
        if (revs->no_walk)
                return 0;
@@ -523,6 +558,12 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
        free_patch_ids(&ids);
 }
 
+static void add_to_list(struct commit_list **p, struct commit *commit, struct commit_list *n)
+{
+       p = &commit_list_insert(commit, p)->next;
+       *p = n;
+}
+
 static int limit_list(struct rev_info *revs)
 {
        struct commit_list *list = revs->commits;
@@ -533,6 +574,7 @@ static int limit_list(struct rev_info *revs)
                struct commit_list *entry = list;
                struct commit *commit = list->item;
                struct object *obj = &commit->object;
+               show_early_output_fn_t show;
 
                list = list->next;
                free(entry);
@@ -543,13 +585,24 @@ static int limit_list(struct rev_info *revs)
                        return -1;
                if (obj->flags & UNINTERESTING) {
                        mark_parents_uninteresting(commit);
-                       if (everybody_uninteresting(list))
+                       if (everybody_uninteresting(list)) {
+                               if (revs->show_all)
+                                       add_to_list(p, commit, list);
                                break;
-                       continue;
+                       }
+                       if (!revs->show_all)
+                               continue;
                }
                if (revs->min_age != -1 && (commit->date > revs->min_age))
                        continue;
                p = &commit_list_insert(commit, p)->next;
+
+               show = show_early_output;
+               if (!show)
+                       continue;
+
+               show(revs, newlist);
+               show_early_output = NULL;
        }
        if (revs->cherry_pick)
                cherry_pick_list(newlist, revs);
@@ -662,8 +715,8 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->abbrev = DEFAULT_ABBREV;
        revs->ignore_merges = 1;
        revs->simplify_history = 1;
-       revs->pruning.recursive = 1;
-       revs->pruning.quiet = 1;
+       DIFF_OPT_SET(&revs->pruning, RECURSIVE);
+       DIFF_OPT_SET(&revs->pruning, QUIET);
        revs->pruning.add_remove = file_add_remove;
        revs->pruning.change = file_change;
        revs->lifo = 1;
@@ -674,12 +727,6 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->skip_count = -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;
-
        revs->commit_format = CMIT_FMT_DEFAULT;
 
        diff_setup(&revs->diffopt);
@@ -994,6 +1041,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                revs->topo_order = 1;
                                continue;
                        }
+                       if (!prefixcmp(arg, "--early-output")) {
+                               int count = 100;
+                               switch (arg[14]) {
+                               case '=':
+                                       count = atoi(arg+15);
+                                       /* Fallthrough */
+                               case 0:
+                                       revs->topo_order = 1;
+                                       revs->early_output = count;
+                                       continue;
+                               }
+                       }
                        if (!strcmp(arg, "--parents")) {
                                revs->parents = 1;
                                continue;
@@ -1006,6 +1065,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                revs->dense = 0;
                                continue;
                        }
+                       if (!strcmp(arg, "--show-all")) {
+                               revs->show_all = 1;
+                               continue;
+                       }
                        if (!strcmp(arg, "--remove-empty")) {
                                revs->remove_empty_trees = 1;
                                continue;
@@ -1054,13 +1117,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!strcmp(arg, "-r")) {
                                revs->diff = 1;
-                               revs->diffopt.recursive = 1;
+                               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
                                continue;
                        }
                        if (!strcmp(arg, "-t")) {
                                revs->diff = 1;
-                               revs->diffopt.recursive = 1;
-                               revs->diffopt.tree_in_recursive = 1;
+                               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
+                               DIFF_OPT_SET(&revs->diffopt, TREE_IN_RECURSIVE);
                                continue;
                        }
                        if (!strcmp(arg, "-m")) {
@@ -1241,8 +1304,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
        if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)
                revs->diff = 1;
 
-       /* Pickaxe and rename following needs diffs */
-       if (revs->diffopt.pickaxe || revs->diffopt.follow_renames)
+       /* Pickaxe, diff-filter and rename following need diffs */
+       if (revs->diffopt.pickaxe ||
+           revs->diffopt.filter ||
+           DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
                revs->diff = 1;
 
        if (revs->topo_order)
@@ -1251,8 +1316,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
        if (revs->prune_data) {
                diff_tree_setup_paths(revs->prune_data, &revs->pruning);
                /* Can't prune commits with rename following: the paths change.. */
-               if (!revs->diffopt.follow_renames)
-                       revs->prune_fn = try_to_simplify_commit;
+               if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
+                       revs->prune = 1;
                if (!revs->full_diff)
                        diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
        }
@@ -1303,9 +1368,7 @@ int prepare_revision_walk(struct rev_info *revs)
                if (limit_list(revs) < 0)
                        return -1;
        if (revs->topo_order)
-               sort_in_topological_order_fn(&revs->commits, revs->lifo,
-                                            revs->topo_setter,
-                                            revs->topo_getter);
+               sort_in_topological_order(&revs->commits, revs->lifo);
        return 0;
 }
 
@@ -1324,7 +1387,9 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
                                return rewrite_one_error;
                if (p->parents && p->parents->next)
                        return rewrite_one_ok;
-               if (p->object.flags & (TREECHANGE | UNINTERESTING))
+               if (p->object.flags & UNINTERESTING)
+                       return rewrite_one_ok;
+               if (!(p->object.flags & TREESAME))
                        return rewrite_one_ok;
                if (!p->parents)
                        return rewrite_one_noparents;
@@ -1381,6 +1446,38 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                           commit->buffer, strlen(commit->buffer));
 }
 
+enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+{
+       if (commit->object.flags & SHOWN)
+               return commit_ignore;
+       if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed))
+               return commit_ignore;
+       if (revs->show_all)
+               return commit_show;
+       if (commit->object.flags & UNINTERESTING)
+               return commit_ignore;
+       if (revs->min_age != -1 && (commit->date > revs->min_age))
+               return commit_ignore;
+       if (revs->no_merges && commit->parents && commit->parents->next)
+               return commit_ignore;
+       if (!commit_match(commit, revs))
+               return commit_ignore;
+       if (revs->prune && revs->dense) {
+               /* Commit without changes? */
+               if (commit->object.flags & TREESAME) {
+                       /* drop merges unless we want parenthood */
+                       if (!revs->parents)
+                               return commit_ignore;
+                       /* non-merge - always ignore it */
+                       if (!commit->parents || !commit->parents->next)
+                               return commit_ignore;
+               }
+               if (revs->parents && rewrite_parents(revs, commit) < 0)
+                       return commit_error;
+       }
+       return commit_show;
+}
+
 static struct commit *get_revision_1(struct rev_info *revs)
 {
        if (!revs->commits)
@@ -1408,36 +1505,15 @@ static struct commit *get_revision_1(struct rev_info *revs)
                        if (add_parents_to_list(revs, commit, &revs->commits) < 0)
                                return NULL;
                }
-               if (commit->object.flags & SHOWN)
-                       continue;
-
-               if (revs->unpacked && has_sha1_pack(commit->object.sha1,
-                                                   revs->ignore_packed))
-                   continue;
 
-               if (commit->object.flags & UNINTERESTING)
-                       continue;
-               if (revs->min_age != -1 && (commit->date > revs->min_age))
-                       continue;
-               if (revs->no_merges &&
-                   commit->parents && commit->parents->next)
-                       continue;
-               if (!commit_match(commit, revs))
+               switch (simplify_commit(revs, commit)) {
+               case commit_ignore:
                        continue;
-               if (revs->prune_fn && revs->dense) {
-                       /* Commit without changes? */
-                       if (!(commit->object.flags & TREECHANGE)) {
-                               /* drop merges unless we want parenthood */
-                               if (!revs->parents)
-                                       continue;
-                               /* non-merge - always ignore it */
-                               if (!commit->parents || !commit->parents->next)
-                                       continue;
-                       }
-                       if (revs->parents && rewrite_parents(revs, commit) < 0)
-                               return NULL;
+               case commit_error:
+                       return NULL;
+               default:
+                       return commit;
                }
-               return commit;
        } while (revs->commits);
        return NULL;
 }