pack-objects: further work on internal rev-list logic.
authorJunio C Hamano <junkio@cox.net>
Wed, 6 Sep 2006 08:42:23 +0000 (01:42 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 7 Sep 2006 09:46:02 +0000 (02:46 -0700)
This teaches the internal rev-list logic to understand options
that are needed for pack handling: --all, --unpacked, and --thin.

It also moves two functions from builtin-rev-list to list-objects
so that the two programs can share more code.

Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-pack-objects.c
builtin-rev-list.c
list-objects.c
list-objects.h

index b6e5960..753dd9a 100644 (file)
@@ -69,6 +69,7 @@ static int progress = 1;
 static volatile sig_atomic_t progress_update;
 static int window = 10;
 static int pack_to_stdout;
+static int num_preferred_base;
 
 /*
  * The object names in objects array are hashed with this hashtable,
@@ -841,7 +842,7 @@ static int check_pbase_path(unsigned hash)
        return 0;
 }
 
-static void add_preferred_base_object(char *name, unsigned hash)
+static void add_preferred_base_object(const char *name, unsigned hash)
 {
        struct pbase_tree *it;
        int cmplen = name_cmp_len(name);
@@ -870,6 +871,9 @@ static void add_preferred_base(unsigned char *sha1)
        unsigned long size;
        unsigned char tree_sha1[20];
 
+       if (window <= num_preferred_base++)
+               return;
+
        data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
        if (!data)
                return;
@@ -1331,7 +1335,6 @@ static int git_pack_config(const char *k, const char *v)
 
 static void read_object_list_from_stdin(void)
 {
-       int num_preferred_base = 0;
        char line[40 + 1 + PATH_MAX + 2];
        unsigned char sha1[20];
        unsigned hash;
@@ -1351,8 +1354,7 @@ static void read_object_list_from_stdin(void)
                        if (get_sha1_hex(line+1, sha1))
                                die("expected edge sha1, got garbage:\n %s",
                                    line);
-                       if (num_preferred_base++ < window)
-                               add_preferred_base(sha1);
+                       add_preferred_base(sha1);
                        continue;
                }
                if (get_sha1_hex(line, sha1))
@@ -1364,71 +1366,36 @@ static void read_object_list_from_stdin(void)
        }
 }
 
-/* copied from rev-list but needs to do things slightly differently */
-static void mark_edge_parents_uninteresting(struct commit *commit)
-{
-       struct commit_list *parents;
-
-       for (parents = commit->parents; parents; parents = parents->next) {
-               struct commit *parent = parents->item;
-               if (!(parent->object.flags & UNINTERESTING))
-                       continue;
-               mark_tree_uninteresting(parent->tree);
-       }
-}
-
-static void mark_edges_uninteresting(struct commit_list *list)
-{
-       for ( ; list; list = list->next) {
-               struct commit *commit = list->item;
-
-               if (commit->object.flags & UNINTERESTING) {
-                       mark_tree_uninteresting(commit->tree);
-                       continue;
-               }
-               mark_edge_parents_uninteresting(commit);
-       }
-}
-
 static void show_commit(struct commit *commit)
 {
        unsigned hash = name_hash("");
+       add_preferred_base_object("", hash);
        add_object_entry(commit->object.sha1, hash, 0);
 }
 
 static void show_object(struct object_array_entry *p)
 {
        unsigned hash = name_hash(p->name);
+       add_preferred_base_object(p->name, hash);
        add_object_entry(p->item->sha1, hash, 0);
 }
 
-static void get_object_list(int unpacked, int all)
+static void show_edge(struct commit *commit)
+{
+       add_preferred_base(commit->object.sha1);
+}
+
+static void get_object_list(int ac, const char **av)
 {
        struct rev_info revs;
        char line[1000];
-       const char *av[6];
-       int ac;
        int flags = 0;
 
-       av[0] = "pack-objects";
-       av[1] = "--objects";
-       ac = 2;
-       if (unpacked)
-               av[ac++] = "--unpacked";
-       if (all)
-               av[ac++] = "--all";
-       av[ac++] = "--stdin";
-       av[ac] = NULL;
-
        init_revisions(&revs, NULL);
        save_commit_buffer = 0;
        track_object_refs = 0;
        setup_revisions(ac, av, &revs, NULL);
 
-       /* make sure we did not get pathspecs */
-       if (revs.prune_data)
-               die("pathspec given");
-
        while (fgets(line, sizeof(line), stdin) != NULL) {
                int len = strlen(line);
                if (line[len - 1] == '\n')
@@ -1447,8 +1414,7 @@ static void get_object_list(int unpacked, int all)
        }
 
        prepare_revision_walk(&revs);
-       mark_edges_uninteresting(revs.commits);
-
+       mark_edges_uninteresting(revs.commits, &revs, show_edge);
        traverse_commit_list(&revs, show_commit, show_object);
 }
 
@@ -1458,9 +1424,14 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        int depth = 10;
        struct object_entry **list;
        int use_internal_rev_list = 0;
-       int unpacked = 0;
-       int all = 0;
+       int thin = 0;
        int i;
+       const char *rp_av[64];
+       int rp_ac;
+
+       rp_av[0] = "pack-objects";
+       rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
+       rp_ac = 2;
 
        git_config(git_pack_config);
 
@@ -1521,12 +1492,19 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        use_internal_rev_list = 1;
                        continue;
                }
-               if (!strcmp("--unpacked", arg)) {
-                       unpacked = 1;
+               if (!strcmp("--unpacked", arg) ||
+                   !strncmp("--unpacked=", arg, 11) ||
+                   !strcmp("--all", arg)) {
+                       use_internal_rev_list = 1;
+                       if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
+                               die("too many internal rev-list options");
+                       rp_av[rp_ac++] = arg;
                        continue;
                }
-               if (!strcmp("--all", arg)) {
-                       all = 1;
+               if (!strcmp("--thin", arg)) {
+                       use_internal_rev_list = 1;
+                       thin = 1;
+                       rp_av[1] = "--objects-edge";
                        continue;
                }
                usage(pack_usage);
@@ -1551,9 +1529,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (pack_to_stdout != !base_name)
                usage(pack_usage);
 
-       /* --unpacked and --all makes sense only with --revs */
-       if (!use_internal_rev_list && (unpacked || all))
-               usage(pack_usage);
+       if (!pack_to_stdout && thin)
+               die("--thin cannot be used to build an indexable pack.");
 
        prepare_packed_git();
 
@@ -1564,8 +1541,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 
        if (!use_internal_rev_list)
                read_object_list_from_stdin();
-       else
-               get_object_list(unpacked, all);
+       else {
+               rp_av[rp_ac] = NULL;
+               get_object_list(rp_ac, rp_av);
+       }
 
        if (progress)
                fprintf(stderr, "Done counting %d objects.\n", nr_objects);
index 0900737..1f3333d 100644 (file)
@@ -114,6 +114,11 @@ static void show_object(struct object_array_entry *p)
                printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
 }
 
+static void show_edge(struct commit *commit)
+{
+       printf("-%s\n", sha1_to_hex(commit->object.sha1));
+}
+
 /*
  * This is a truly stupid algorithm, but it's only
  * used for bisection, and we just don't care enough.
@@ -192,35 +197,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
        return best;
 }
 
-static void mark_edge_parents_uninteresting(struct commit *commit)
-{
-       struct commit_list *parents;
-
-       for (parents = commit->parents; parents; parents = parents->next) {
-               struct commit *parent = parents->item;
-               if (!(parent->object.flags & UNINTERESTING))
-                       continue;
-               mark_tree_uninteresting(parent->tree);
-               if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
-                       parent->object.flags |= SHOWN;
-                       printf("-%s\n", sha1_to_hex(parent->object.sha1));
-               }
-       }
-}
-
-static void mark_edges_uninteresting(struct commit_list *list)
-{
-       for ( ; list; list = list->next) {
-               struct commit *commit = list->item;
-
-               if (commit->object.flags & UNINTERESTING) {
-                       mark_tree_uninteresting(commit->tree);
-                       continue;
-               }
-               mark_edge_parents_uninteresting(commit);
-       }
-}
-
 static void read_revisions_from_stdin(struct rev_info *revs)
 {
        char line[1000];
@@ -300,7 +276,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 
        prepare_revision_walk(&revs);
        if (revs.tree_objects)
-               mark_edges_uninteresting(revs.commits);
+               mark_edges_uninteresting(revs.commits, &revs, show_edge);
 
        if (bisect_list)
                revs.commits = find_bisection(revs.commits);
index adaf997..f1fa21c 100644 (file)
@@ -66,6 +66,39 @@ static void process_tree(struct rev_info *revs,
        tree->buffer = NULL;
 }
 
+static void mark_edge_parents_uninteresting(struct commit *commit,
+                                           struct rev_info *revs,
+                                           show_edge_fn show_edge)
+{
+       struct commit_list *parents;
+
+       for (parents = commit->parents; parents; parents = parents->next) {
+               struct commit *parent = parents->item;
+               if (!(parent->object.flags & UNINTERESTING))
+                       continue;
+               mark_tree_uninteresting(parent->tree);
+               if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
+                       parent->object.flags |= SHOWN;
+                       show_edge(parent);
+               }
+       }
+}
+
+void mark_edges_uninteresting(struct commit_list *list,
+                             struct rev_info *revs,
+                             show_edge_fn show_edge)
+{
+       for ( ; list; list = list->next) {
+               struct commit *commit = list->item;
+
+               if (commit->object.flags & UNINTERESTING) {
+                       mark_tree_uninteresting(commit->tree);
+                       continue;
+               }
+               mark_edge_parents_uninteresting(commit, revs, show_edge);
+       }
+}
+
 void traverse_commit_list(struct rev_info *revs,
                          void (*show_commit)(struct commit *),
                          void (*show_object)(struct object_array_entry *))
index 8a5fae6..0f41391 100644 (file)
@@ -1,8 +1,12 @@
 #ifndef LIST_OBJECTS_H
 #define LIST_OBJECTS_H
 
-void traverse_commit_list(struct rev_info *revs,
-                         void (*show_commit)(struct commit *),
-                         void (*show_object)(struct object_array_entry *));
+typedef void (*show_commit_fn)(struct commit *);
+typedef void (*show_object_fn)(struct object_array_entry *);
+typedef void (*show_edge_fn)(struct commit *);
+
+void traverse_commit_list(struct rev_info *revs, show_commit_fn, show_object_fn);
+
+void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
 
 #endif