Merge branch 'nb/branch-show-other-worktrees-head'
[gitweb.git] / list-objects.c
index a2296a8e7b42a3d5d044c648d353ac94f9b4ed81..b5651ddd5bfdd6cda4047f71cc3cb66fc31a793d 100644 (file)
@@ -125,6 +125,11 @@ static void process_tree_contents(struct traversal_context *ctx,
 
                if (S_ISDIR(entry.mode)) {
                        struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
+                       if (!t) {
+                               die(_("entry '%s' in tree %s has tree mode, "
+                                     "but is not a tree"),
+                                   entry.path, oid_to_hex(&tree->object.oid));
+                       }
                        t->object.flags |= NOT_USER_GIVEN;
                        process_tree(ctx, t, base, entry.path);
                }
@@ -133,6 +138,11 @@ static void process_tree_contents(struct traversal_context *ctx,
                                        base, entry.path);
                else {
                        struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
+                       if (!b) {
+                               die(_("entry '%s' in tree %s has blob mode, "
+                                     "but is not a blob"),
+                                   entry.path, oid_to_hex(&tree->object.oid));
+                       }
                        b->object.flags |= NOT_USER_GIVEN;
                        process_blob(ctx, b, base, entry.path);
                }
@@ -226,25 +236,73 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
        }
 }
 
-void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
+static void add_edge_parents(struct commit *commit,
+                            struct rev_info *revs,
+                            show_edge_fn show_edge,
+                            struct oidset *set)
+{
+       struct commit_list *parents;
+
+       for (parents = commit->parents; parents; parents = parents->next) {
+               struct commit *parent = parents->item;
+               struct tree *tree = get_commit_tree(parent);
+
+               if (!tree)
+                       continue;
+
+               oidset_insert(set, &tree->object.oid);
+
+               if (!(parent->object.flags & UNINTERESTING))
+                       continue;
+               tree->object.flags |= UNINTERESTING;
+
+               if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
+                       parent->object.flags |= SHOWN;
+                       show_edge(parent);
+               }
+       }
+}
+
+void mark_edges_uninteresting(struct rev_info *revs,
+                             show_edge_fn show_edge,
+                             int sparse)
 {
        struct commit_list *list;
        int i;
 
-       for (list = revs->commits; list; list = list->next) {
-               struct commit *commit = list->item;
+       if (sparse) {
+               struct oidset set;
+               oidset_init(&set, 16);
 
-               if (commit->object.flags & UNINTERESTING) {
-                       mark_tree_uninteresting(revs->repo,
-                                               get_commit_tree(commit));
-                       if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
-                               commit->object.flags |= SHOWN;
-                               show_edge(commit);
+               for (list = revs->commits; list; list = list->next) {
+                       struct commit *commit = list->item;
+                       struct tree *tree = get_commit_tree(commit);
+
+                       if (commit->object.flags & UNINTERESTING)
+                               tree->object.flags |= UNINTERESTING;
+
+                       oidset_insert(&set, &tree->object.oid);
+                       add_edge_parents(commit, revs, show_edge, &set);
+               }
+
+               mark_trees_uninteresting_sparse(revs->repo, &set);
+               oidset_clear(&set);
+       } else {
+               for (list = revs->commits; list; list = list->next) {
+                       struct commit *commit = list->item;
+                       if (commit->object.flags & UNINTERESTING) {
+                               mark_tree_uninteresting(revs->repo,
+                                                       get_commit_tree(commit));
+                               if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
+                                       commit->object.flags |= SHOWN;
+                                       show_edge(commit);
+                               }
+                               continue;
                        }
-                       continue;
+                       mark_edge_parents_uninteresting(commit, revs, show_edge);
                }
-               mark_edge_parents_uninteresting(commit, revs, show_edge);
        }
+
        if (revs->edge_hint_aggressive) {
                for (i = 0; i < revs->cmdline.nr; i++) {
                        struct object *obj = revs->cmdline.rev[i].item;
@@ -316,6 +374,9 @@ static void do_traverse(struct traversal_context *ctx)
                        struct tree *tree = get_commit_tree(commit);
                        tree->object.flags |= NOT_USER_GIVEN;
                        add_pending_tree(ctx->revs, tree);
+               } else if (commit->object.parsed) {
+                       die(_("unable to load root tree for commit %s"),
+                             oid_to_hex(&commit->object.oid));
                }
                ctx->show_commit(commit, ctx->show_data);