repack: refactor setup of pack-objects cmd
[gitweb.git] / revision.c
index 1cff11833e7e2ce64114e4d18339d6ae21ec80e8..0627494378dcf6d921af59cc83d02e6a6feb0030 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "object-store.h"
 #include "tag.h"
 #include "blob.h"
 #include "tree.h"
@@ -29,6 +30,8 @@ volatile show_early_output_fn_t show_early_output;
 static const char *term_bad;
 static const char *term_good;
 
+implement_shared_commit_slab(revision_sources, char *);
+
 void show_object_with_name(FILE *out, struct object *obj, const char *name)
 {
        const char *p;
@@ -52,21 +55,18 @@ static void mark_tree_contents_uninteresting(struct tree *tree)
 {
        struct tree_desc desc;
        struct name_entry entry;
-       struct object *obj = &tree->object;
 
-       if (!has_object_file(&obj->oid))
+       if (parse_tree_gently(tree, 1) < 0)
                return;
-       if (parse_tree(tree) < 0)
-               die("bad tree %s", oid_to_hex(&obj->oid));
 
        init_tree_desc(&desc, tree->buffer, tree->size);
        while (tree_entry(&desc, &entry)) {
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
-                       mark_tree_uninteresting(lookup_tree(entry.oid));
+                       mark_tree_uninteresting(lookup_tree(the_repository, entry.oid));
                        break;
                case OBJ_BLOB:
-                       mark_blob_uninteresting(lookup_blob(entry.oid));
+                       mark_blob_uninteresting(lookup_blob(the_repository, entry.oid));
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@ -95,50 +95,63 @@ void mark_tree_uninteresting(struct tree *tree)
        mark_tree_contents_uninteresting(tree);
 }
 
-void mark_parents_uninteresting(struct commit *commit)
+struct commit_stack {
+       struct commit **items;
+       size_t nr, alloc;
+};
+#define COMMIT_STACK_INIT { NULL, 0, 0 }
+
+static void commit_stack_push(struct commit_stack *stack, struct commit *commit)
 {
-       struct commit_list *parents = NULL, *l;
+       ALLOC_GROW(stack->items, stack->nr + 1, stack->alloc);
+       stack->items[stack->nr++] = commit;
+}
 
-       for (l = commit->parents; l; l = l->next)
-               commit_list_insert(l->item, &parents);
+static struct commit *commit_stack_pop(struct commit_stack *stack)
+{
+       return stack->nr ? stack->items[--stack->nr] : NULL;
+}
 
-       while (parents) {
-               struct commit *commit = pop_commit(&parents);
+static void commit_stack_clear(struct commit_stack *stack)
+{
+       FREE_AND_NULL(stack->items);
+       stack->nr = stack->alloc = 0;
+}
 
-               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 (!commit->object.parsed &&
-                           !has_object_file(&commit->object.oid))
-                               commit->object.parsed = 1;
+static void mark_one_parent_uninteresting(struct commit *commit,
+                                         struct commit_stack *pending)
+{
+       struct commit_list *l;
 
-                       if (commit->object.flags & UNINTERESTING)
-                               break;
+       if (commit->object.flags & UNINTERESTING)
+               return;
+       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..
+        */
+       for (l = commit->parents; l; l = l->next)
+               commit_stack_push(pending, l->item);
+}
 
-                       commit->object.flags |= UNINTERESTING;
+void mark_parents_uninteresting(struct commit *commit)
+{
+       struct commit_stack pending = COMMIT_STACK_INIT;
+       struct commit_list *l;
 
-                       /*
-                        * 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)
-                               break;
+       for (l = commit->parents; l; l = l->next)
+               mark_one_parent_uninteresting(l->item, &pending);
 
-                       for (l = commit->parents->next; l; l = l->next)
-                               commit_list_insert(l->item, &parents);
-                       commit = commit->parents->item;
-               }
-       }
+       while (pending.nr > 0)
+               mark_one_parent_uninteresting(commit_stack_pop(&pending),
+                                             &pending);
+
+       commit_stack_clear(&pending);
 }
 
 static void add_pending_object_with_path(struct rev_info *revs,
@@ -162,6 +175,7 @@ static void add_pending_object_with_path(struct rev_info *revs,
                strbuf_release(&buf);
                return; /* do not add the commit itself */
        }
+       obj->flags |= USER_GIVEN;
        add_object_array_with_path(obj, name, &revs->pending, mode, path);
 }
 
@@ -184,7 +198,7 @@ void add_head_to_pending(struct rev_info *revs)
        struct object *obj;
        if (get_oid("HEAD", &oid))
                return;
-       obj = parse_object(&oid);
+       obj = parse_object(the_repository, &oid);
        if (!obj)
                return;
        add_pending_object(revs, obj, "HEAD");
@@ -196,7 +210,7 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
 {
        struct object *object;
 
-       object = parse_object(oid);
+       object = parse_object(the_repository, oid);
        if (!object) {
                if (revs->ignore_missing)
                        return object;
@@ -233,10 +247,13 @@ static struct commit *handle_commit(struct rev_info *revs,
                        add_pending_object(revs, object, tag->tag);
                if (!tag->tagged)
                        die("bad tag");
-               object = parse_object(&tag->tagged->oid);
+               object = parse_object(the_repository, &tag->tagged->oid);
                if (!object) {
                        if (revs->ignore_missing_links || (flags & UNINTERESTING))
                                return NULL;
+                       if (revs->exclude_promisor_objects &&
+                           is_promisor_object(&tag->tagged->oid))
+                               return NULL;
                        die("bad object %s", oid_to_hex(&tag->tagged->oid));
                }
                object->flags |= flags;
@@ -255,14 +272,19 @@ static struct commit *handle_commit(struct rev_info *revs,
         */
        if (object->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)object;
+
                if (parse_commit(commit) < 0)
                        die("unable to parse commit %s", name);
                if (flags & UNINTERESTING) {
                        mark_parents_uninteresting(commit);
                        revs->limited = 1;
                }
-               if (revs->show_source && !commit->util)
-                       commit->util = xstrdup(name);
+               if (revs->sources) {
+                       char **slot = revision_sources_at(revs->sources, commit);
+
+                       if (!*slot)
+                               *slot = xstrdup(name);
+               }
                return commit;
        }
 
@@ -441,8 +463,8 @@ static void file_change(struct diff_options *options,
 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;
+       struct tree *t1 = get_commit_tree(parent);
+       struct tree *t2 = get_commit_tree(commit);
 
        if (!t1)
                return REV_TREE_NEW;
@@ -478,7 +500,7 @@ static int rev_compare_tree(struct rev_info *revs,
 static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 {
        int retval;
-       struct tree *t1 = commit->tree;
+       struct tree *t1 = get_commit_tree(commit);
 
        if (!t1)
                return 0;
@@ -616,7 +638,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        if (!revs->prune)
                return;
 
-       if (!commit->tree)
+       if (!get_commit_tree(commit))
                return;
 
        if (!commit->parents) {
@@ -814,8 +836,12 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
                        }
                        return -1;
                }
-               if (revs->show_source && !p->util)
-                       p->util = commit->util;
+               if (revs->sources) {
+                       char **slot = revision_sources_at(revs->sources, p);
+
+                       if (!*slot)
+                               *slot = *revision_sources_at(revs->sources, commit);
+               }
                p->object.flags |= left_flag;
                if (!(p->object.flags & SEEN)) {
                        p->object.flags |= SEEN;
@@ -1227,7 +1253,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
 {
        struct all_refs_cb *cb = cb_data;
        if (!is_null_oid(oid)) {
-               struct object *o = parse_object(oid);
+               struct object *o = parse_object(the_repository, oid);
                if (o) {
                        o->flags |= cb->all_flags;
                        /* ??? CMDLINEFLAGS ??? */
@@ -1300,7 +1326,7 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
        int i;
 
        if (it->entry_count >= 0) {
-               struct tree *tree = lookup_tree(&it->oid);
+               struct tree *tree = lookup_tree(the_repository, &it->oid);
                add_pending_object_with_path(revs, &tree->object, "",
                                             040000, path->buf);
        }
@@ -1326,7 +1352,7 @@ static void do_add_index_objects_to_pending(struct rev_info *revs,
                if (S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               blob = lookup_blob(&ce->oid);
+               blob = lookup_blob(the_repository, &ce->oid);
                if (!blob)
                        die("unable to add index blob to traversal");
                add_pending_object_with_path(revs, &blob->object, "",
@@ -1555,8 +1581,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
                *dotdot = '\0';
        }
 
-       a_obj = parse_object(&a_oid);
-       b_obj = parse_object(&b_oid);
+       a_obj = parse_object(the_repository, &a_oid);
+       b_obj = parse_object(the_repository, &b_oid);
        if (!a_obj || !b_obj)
                return dotdot_missing(arg, dotdot, revs, symmetric);
 
@@ -1569,8 +1595,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
                struct commit *a, *b;
                struct commit_list *exclude;
 
-               a = lookup_commit_reference(&a_obj->oid);
-               b = lookup_commit_reference(&b_obj->oid);
+               a = lookup_commit_reference(the_repository, &a_obj->oid);
+               b = lookup_commit_reference(the_repository, &b_obj->oid);
                if (!a || !b)
                        return dotdot_missing(arg, dotdot, revs, symmetric);
 
@@ -1752,6 +1778,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        const char *arg = argv[0];
        const char *optarg;
        int argcount;
+       const unsigned hexsz = the_hash_algo->hexsz;
 
        /* pseudo revision arguments */
        if (!strcmp(arg, "--all") || !strcmp(arg, "--branches") ||
@@ -2039,8 +2066,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->abbrev = strtoul(optarg, NULL, 10);
                if (revs->abbrev < MINIMUM_ABBREV)
                        revs->abbrev = MINIMUM_ABBREV;
-               else if (revs->abbrev > 40)
-                       revs->abbrev = 40;
+               else if (revs->abbrev > hexsz)
+                       revs->abbrev = hexsz;
        } else if (!strcmp(arg, "--abbrev-commit")) {
                revs->abbrev_commit = 1;
                revs->abbrev_commit_given = 1;
@@ -2108,7 +2135,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->ignore_missing = 1;
        } else if (!strcmp(arg, "--exclude-promisor-objects")) {
                if (fetch_if_missing)
-                       die("BUG: exclude_promisor_objects can only be used when fetch_if_missing is 0");
+                       BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
                revs->exclude_promisor_objects = 1;
        } else {
                int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
@@ -2174,7 +2201,7 @@ static int handle_revision_pseudo_opt(const char *submodule,
                 * supported right now, so stick to single worktree.
                 */
                if (!revs->single_worktree)
-                       die("BUG: --single-worktree cannot be used together with submodule");
+                       BUG("--single-worktree cannot be used together with submodule");
                refs = get_submodule_ref_store(submodule);
        } else
                refs = get_main_ref_store(the_repository);
@@ -2860,7 +2887,7 @@ static int mark_uninteresting(const struct object_id *oid,
                              uint32_t pos,
                              void *unused)
 {
-       struct object *o = parse_object(oid);
+       struct object *o = parse_object(the_repository, oid);
        o->flags |= UNINTERESTING | SEEN;
        return 0;
 }
@@ -3087,7 +3114,7 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
 {
        if (commit->object.flags & SHOWN)
                return commit_ignore;
-       if (revs->unpacked && has_sha1_pack(commit->object.oid.hash))
+       if (revs->unpacked && has_object_pack(&commit->object.oid))
                return commit_ignore;
        if (commit->object.flags & UNINTERESTING)
                return commit_ignore;