rev-list: add --indexed-objects option
[gitweb.git] / revision.c
index 2571ada6bf66ce6e945c539be4b0123e5b9648a9..a2337f8ff98342e56293a81513bf91d41e71ec36 100644 (file)
@@ -17,6 +17,7 @@
 #include "mailmap.h"
 #include "commit-slab.h"
 #include "dir.h"
+#include "cache-tree.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -198,9 +199,10 @@ void mark_parents_uninteresting(struct commit *commit)
        }
 }
 
-static void add_pending_object_with_mode(struct rev_info *revs,
+static void add_pending_object_with_path(struct rev_info *revs,
                                         struct object *obj,
-                                        const char *name, unsigned mode)
+                                        const char *name, unsigned mode,
+                                        const char *path)
 {
        if (!obj)
                return;
@@ -220,7 +222,14 @@ static void add_pending_object_with_mode(struct rev_info *revs,
                if (st)
                        return;
        }
-       add_object_array_with_mode(obj, name, &revs->pending, mode);
+       add_object_array_with_path(obj, name, &revs->pending, mode, path);
+}
+
+static void add_pending_object_with_mode(struct rev_info *revs,
+                                        struct object *obj,
+                                        const char *name, unsigned mode)
+{
+       add_pending_object_with_path(revs, obj, name, mode, NULL);
 }
 
 void add_pending_object(struct rev_info *revs,
@@ -265,8 +274,12 @@ void add_pending_sha1(struct rev_info *revs, const char *name,
 }
 
 static struct commit *handle_commit(struct rev_info *revs,
-                                   struct object *object, const char *name)
+                                   struct object_array_entry *entry)
 {
+       struct object *object = entry->item;
+       const char *name = entry->name;
+       const char *path = entry->path;
+       unsigned int mode = entry->mode;
        unsigned long flags = object->flags;
 
        /*
@@ -285,6 +298,14 @@ static struct commit *handle_commit(struct rev_info *revs,
                        die("bad object %s", sha1_to_hex(tag->tagged->sha1));
                }
                object->flags |= flags;
+               /*
+                * We'll handle the tagged object by looping or dropping
+                * through to the non-tag handlers below. Do not
+                * propagate data from the tag's pending entry.
+                */
+               name = "";
+               path = NULL;
+               mode = 0;
        }
 
        /*
@@ -300,7 +321,7 @@ static struct commit *handle_commit(struct rev_info *revs,
                        revs->limited = 1;
                }
                if (revs->show_source && !commit->util)
-                       commit->util = (void *) name;
+                       commit->util = xstrdup(name);
                return commit;
        }
 
@@ -316,7 +337,7 @@ static struct commit *handle_commit(struct rev_info *revs,
                        mark_tree_contents_uninteresting(tree);
                        return NULL;
                }
-               add_pending_object(revs, object, "");
+               add_pending_object_with_path(revs, object, name, mode, path);
                return NULL;
        }
 
@@ -328,7 +349,7 @@ static struct commit *handle_commit(struct rev_info *revs,
                        return NULL;
                if (flags & UNINTERESTING)
                        return NULL;
-               add_pending_object(revs, object, "");
+               add_pending_object_with_path(revs, object, name, mode, path);
                return NULL;
        }
        die("%s is unknown object", name);
@@ -473,7 +494,7 @@ static int rev_compare_tree(struct rev_info *revs,
                 * 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))
+               if (get_name_decoration(&commit->object))
                        return REV_TREE_DIFFERENT;
                /*
                 * A commit that is not pointed by a tag is uninteresting
@@ -1275,7 +1296,7 @@ static int handle_one_reflog(const char *path, const unsigned char *sha1, int fl
        return 0;
 }
 
-static void handle_reflog(struct rev_info *revs, unsigned flags)
+void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
 {
        struct all_refs_cb cb;
        cb.all_revs = revs;
@@ -1283,6 +1304,53 @@ static void handle_reflog(struct rev_info *revs, unsigned flags)
        for_each_reflog(handle_one_reflog, &cb);
 }
 
+static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
+                          struct strbuf *path)
+{
+       size_t baselen = path->len;
+       int i;
+
+       if (it->entry_count >= 0) {
+               struct tree *tree = lookup_tree(it->sha1);
+               add_pending_object_with_path(revs, &tree->object, "",
+                                            040000, path->buf);
+       }
+
+       for (i = 0; i < it->subtree_nr; i++) {
+               struct cache_tree_sub *sub = it->down[i];
+               strbuf_addf(path, "%s%s", baselen ? "/" : "", sub->name);
+               add_cache_tree(sub->cache_tree, revs, path);
+               strbuf_setlen(path, baselen);
+       }
+
+}
+
+void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
+{
+       int i;
+
+       read_cache();
+       for (i = 0; i < active_nr; i++) {
+               struct cache_entry *ce = active_cache[i];
+               struct blob *blob;
+
+               if (S_ISGITLINK(ce->ce_mode))
+                       continue;
+
+               blob = lookup_blob(ce->sha1);
+               if (!blob)
+                       die("unable to add index blob to traversal");
+               add_pending_object_with_path(revs, &blob->object, "",
+                                            ce->ce_mode, ce->name);
+       }
+
+       if (active_cache_tree) {
+               struct strbuf path = STRBUF_INIT;
+               add_cache_tree(active_cache_tree, revs, &path);
+               strbuf_release(&path);
+       }
+}
+
 static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
 {
        unsigned char sha1[20];
@@ -1397,7 +1465,7 @@ static void prepare_show_merge(struct rev_info *revs)
                        continue;
                if (ce_path_match(ce, &revs->prune_data, NULL)) {
                        prune_num++;
-                       prune = xrealloc(prune, sizeof(*prune) * prune_num);
+                       REALLOC_ARRAY(prune, prune_num);
                        prune[prune_num-2] = ce->name;
                        prune[prune_num-1] = NULL;
                }
@@ -1633,6 +1701,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
            !strcmp(arg, "--reflog") || !strcmp(arg, "--not") ||
            !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
            !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
+           !strcmp(arg, "--indexed-objects") ||
            starts_with(arg, "--exclude=") ||
            starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
            starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
@@ -1825,7 +1894,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if (!strcmp(arg, "--pretty")) {
                revs->verbose_header = 1;
                revs->pretty_given = 1;
-               get_commit_format(arg+8, revs);
+               get_commit_format(NULL, revs);
        } else if (starts_with(arg, "--pretty=") || starts_with(arg, "--format=")) {
                /*
                 * Detached form ("--pretty X" as opposed to "--pretty=X")
@@ -2061,7 +2130,9 @@ static int handle_revision_pseudo_opt(const char *submodule,
                for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--reflog")) {
-               handle_reflog(revs, *flags);
+               add_reflogs_to_pending(revs, *flags);
+       } else if (!strcmp(arg, "--indexed-objects")) {
+               add_index_objects_to_pending(revs, *flags);
        } else if (!strcmp(arg, "--not")) {
                *flags ^= UNINTERESTING | BOTTOM;
        } else if (!strcmp(arg, "--no-walk")) {
@@ -2656,26 +2727,26 @@ void reset_revision_walk(void)
 
 int prepare_revision_walk(struct rev_info *revs)
 {
-       int nr = revs->pending.nr;
-       struct object_array_entry *e, *list;
+       int i;
+       struct object_array old_pending;
        struct commit_list **next = &revs->commits;
 
-       e = list = revs->pending.objects;
+       memcpy(&old_pending, &revs->pending, sizeof(old_pending));
        revs->pending.nr = 0;
        revs->pending.alloc = 0;
        revs->pending.objects = NULL;
-       while (--nr >= 0) {
-               struct commit *commit = handle_commit(revs, e->item, e->name);
+       for (i = 0; i < old_pending.nr; i++) {
+               struct object_array_entry *e = old_pending.objects + i;
+               struct commit *commit = handle_commit(revs, e);
                if (commit) {
                        if (!(commit->object.flags & SEEN)) {
                                commit->object.flags |= SEEN;
                                next = commit_list_append(commit, next);
                        }
                }
-               e++;
        }
        if (!revs->leak_pending)
-               free(list);
+               object_array_clear(&old_pending);
 
        /* Signal whether we need per-parent treesame decoration */
        if (revs->simplify_merges ||