Merge branch 'jc/pack'
authorJunio C Hamano <junkio@cox.net>
Mon, 18 Sep 2006 01:32:03 +0000 (18:32 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 18 Sep 2006 01:32:03 +0000 (18:32 -0700)
* jc/pack:
pack-objects: document --revs, --unpacked and --all.
pack-objects --unpacked=<existing pack> option.
pack-objects: further work on internal rev-list logic.
pack-objects: run rev-list equivalent internally.
Separate object listing routines out of rev-list

12 files changed:
Documentation/git-pack-objects.txt
Makefile
builtin-count-objects.c
builtin-pack-objects.c
builtin-prune-packed.c
builtin-rev-list.c
cache.h
list-objects.c [new file with mode: 0644]
list-objects.h [new file with mode: 0644]
revision.c
revision.h
sha1_file.c
index 4991f88c92b3d9f374f1a7e4a8aa8178a134f49f..d4661ddc2f84c1392b32ad3fdf5f4ebe5b465e00 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty]
        [--local] [--incremental] [--window=N] [--depth=N]
-       {--stdout | base-name} < object-list
+       [--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
 
 
 DESCRIPTION
@@ -56,6 +56,24 @@ base-name::
        Write the pack contents (what would have been written to
        .pack file) out to the standard output.
 
+--revs::
+       Read the revision arguments from the standard input, instead of
+       individual object names.  The revision arguments are processed
+       the same way as gitlink:git-rev-list[1] with `--objects` flag
+       uses its `commit` arguments to build the list of objects it
+       outputs.  The objects on the resulting list are packed.
+
+--unpacked::
+       This implies `--revs`.  When processing the list of
+       revision arguments read from the standard input, limit
+       the objects packed to those that are not already packed.
+
+--all::
+       This implies `--revs`.  In addition to the list of
+       revision arguments read from the standard input, pretend
+       as if all refs under `$GIT_DIR/refs` are specifed to be
+       included.
+
 --window and --depth::
        These two options affects how the objects contained in
        the pack are stored using delta compression.  The
@@ -103,6 +121,7 @@ Documentation by Junio C Hamano
 
 See Also
 --------
+gitlink:git-rev-list[1]
 gitlink:git-repack[1]
 gitlink:git-prune-packed[1]
 
index 69915d865168817f72c084f15930e41bf5b9ad45..8467447da90f04cc55d1403ea102c6335331aa52 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -235,7 +235,7 @@ XDIFF_LIB=xdiff/lib.a
 
 LIB_H = \
        archive.h blob.h cache.h commit.h csum-file.h delta.h \
-       diff.h object.h pack.h pkt-line.h quote.h refs.h sideband.h \
+       diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
        tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
 
@@ -252,7 +252,7 @@ LIB_OBJS = \
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
-       write_or_die.o trace.o \
+       write_or_die.o trace.o list-objects.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
        color.o wt-status.o
 
index 1d3729aa9914d6c68dbb6ad11cb46504b4a688e0..73c59824238f58c2dc94544ef67ea51741d834ac 100644 (file)
@@ -62,7 +62,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
                hex[40] = 0;
                if (get_sha1_hex(hex, sha1))
                        die("internal error");
-               if (has_sha1_pack(sha1))
+               if (has_sha1_pack(sha1, NULL))
                        (*packed_loose)++;
        }
 }
index 149fa283971712650f124e96aa5bf9e2f99b0ebb..8d7a1209d5effe83eb93ad4d0f5088806d625c70 100644 (file)
@@ -9,10 +9,13 @@
 #include "pack.h"
 #include "csum-file.h"
 #include "tree-walk.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
 #include <sys/time.h>
 #include <signal.h>
 
-static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
+static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
 
 struct object_entry {
        unsigned char sha1[20];
@@ -66,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,
@@ -838,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);
@@ -867,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;
@@ -1326,14 +1333,105 @@ static int git_pack_config(const char *k, const char *v)
        return git_default_config(k, v);
 }
 
+static void read_object_list_from_stdin(void)
+{
+       char line[40 + 1 + PATH_MAX + 2];
+       unsigned char sha1[20];
+       unsigned hash;
+
+       for (;;) {
+               if (!fgets(line, sizeof(line), stdin)) {
+                       if (feof(stdin))
+                               break;
+                       if (!ferror(stdin))
+                               die("fgets returned NULL, not EOF, not error!");
+                       if (errno != EINTR)
+                               die("fgets: %s", strerror(errno));
+                       clearerr(stdin);
+                       continue;
+               }
+               if (line[0] == '-') {
+                       if (get_sha1_hex(line+1, sha1))
+                               die("expected edge sha1, got garbage:\n %s",
+                                   line);
+                       add_preferred_base(sha1);
+                       continue;
+               }
+               if (get_sha1_hex(line, sha1))
+                       die("expected sha1, got garbage:\n %s", line);
+
+               hash = name_hash(line+41);
+               add_preferred_base_object(line+41, hash);
+               add_object_entry(sha1, hash, 0);
+       }
+}
+
+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 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];
+       int flags = 0;
+
+       init_revisions(&revs, NULL);
+       save_commit_buffer = 0;
+       track_object_refs = 0;
+       setup_revisions(ac, av, &revs, NULL);
+
+       while (fgets(line, sizeof(line), stdin) != NULL) {
+               int len = strlen(line);
+               if (line[len - 1] == '\n')
+                       line[--len] = 0;
+               if (!len)
+                       break;
+               if (*line == '-') {
+                       if (!strcmp(line, "--not")) {
+                               flags ^= UNINTERESTING;
+                               continue;
+                       }
+                       die("not a rev '%s'", line);
+               }
+               if (handle_revision_arg(line, &revs, flags, 1))
+                       die("bad revision '%s'", line);
+       }
+
+       prepare_revision_walk(&revs);
+       mark_edges_uninteresting(revs.commits, &revs, show_edge);
+       traverse_commit_list(&revs, show_commit, show_object);
+}
+
 int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 {
        SHA_CTX ctx;
-       char line[40 + 1 + PATH_MAX + 2];
        int depth = 10;
        struct object_entry **list;
-       int num_preferred_base = 0;
+       int use_internal_rev_list = 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);
 
@@ -1341,63 +1439,99 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
-               if (*arg == '-') {
-                       if (!strcmp("--non-empty", arg)) {
-                               non_empty = 1;
-                               continue;
-                       }
-                       if (!strcmp("--local", arg)) {
-                               local = 1;
-                               continue;
-                       }
-                       if (!strcmp("--progress", arg)) {
-                               progress = 1;
-                               continue;
-                       }
-                       if (!strcmp("--incremental", arg)) {
-                               incremental = 1;
-                               continue;
-                       }
-                       if (!strncmp("--window=", arg, 9)) {
-                               char *end;
-                               window = strtoul(arg+9, &end, 0);
-                               if (!arg[9] || *end)
-                                       usage(pack_usage);
-                               continue;
-                       }
-                       if (!strncmp("--depth=", arg, 8)) {
-                               char *end;
-                               depth = strtoul(arg+8, &end, 0);
-                               if (!arg[8] || *end)
-                                       usage(pack_usage);
-                               continue;
-                       }
-                       if (!strcmp("--progress", arg)) {
-                               progress = 1;
-                               continue;
-                       }
-                       if (!strcmp("-q", arg)) {
-                               progress = 0;
-                               continue;
-                       }
-                       if (!strcmp("--no-reuse-delta", arg)) {
-                               no_reuse_delta = 1;
-                               continue;
-                       }
-                       if (!strcmp("--stdout", arg)) {
-                               pack_to_stdout = 1;
-                               continue;
-                       }
-                       usage(pack_usage);
+               if (*arg != '-')
+                       break;
+
+               if (!strcmp("--non-empty", arg)) {
+                       non_empty = 1;
+                       continue;
+               }
+               if (!strcmp("--local", arg)) {
+                       local = 1;
+                       continue;
+               }
+               if (!strcmp("--progress", arg)) {
+                       progress = 1;
+                       continue;
+               }
+               if (!strcmp("--incremental", arg)) {
+                       incremental = 1;
+                       continue;
+               }
+               if (!strncmp("--window=", arg, 9)) {
+                       char *end;
+                       window = strtoul(arg+9, &end, 0);
+                       if (!arg[9] || *end)
+                               usage(pack_usage);
+                       continue;
+               }
+               if (!strncmp("--depth=", arg, 8)) {
+                       char *end;
+                       depth = strtoul(arg+8, &end, 0);
+                       if (!arg[8] || *end)
+                               usage(pack_usage);
+                       continue;
+               }
+               if (!strcmp("--progress", arg)) {
+                       progress = 1;
+                       continue;
+               }
+               if (!strcmp("-q", arg)) {
+                       progress = 0;
+                       continue;
+               }
+               if (!strcmp("--no-reuse-delta", arg)) {
+                       no_reuse_delta = 1;
+                       continue;
+               }
+               if (!strcmp("--stdout", arg)) {
+                       pack_to_stdout = 1;
+                       continue;
+               }
+               if (!strcmp("--revs", arg)) {
+                       use_internal_rev_list = 1;
+                       continue;
+               }
+               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 (base_name)
-                       usage(pack_usage);
-               base_name = arg;
+               if (!strcmp("--thin", arg)) {
+                       use_internal_rev_list = 1;
+                       thin = 1;
+                       rp_av[1] = "--objects-edge";
+                       continue;
+               }
+               usage(pack_usage);
        }
 
+       /* Traditionally "pack-objects [options] base extra" failed;
+        * we would however want to take refs parameter that would
+        * have been given to upstream rev-list ourselves, which means
+        * we somehow want to say what the base name is.  So the
+        * syntax would be:
+        *
+        * pack-objects [options] base <refs...>
+        *
+        * in other words, we would treat the first non-option as the
+        * base_name and send everything else to the internal revision
+        * walker.
+        */
+
+       if (!pack_to_stdout)
+               base_name = argv[i++];
+
        if (pack_to_stdout != !base_name)
                usage(pack_usage);
 
+       if (!pack_to_stdout && thin)
+               die("--thin cannot be used to build an indexable pack.");
+
        prepare_packed_git();
 
        if (progress) {
@@ -1405,35 +1539,13 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                setup_progress_signal();
        }
 
-       for (;;) {
-               unsigned char sha1[20];
-               unsigned hash;
-
-               if (!fgets(line, sizeof(line), stdin)) {
-                       if (feof(stdin))
-                               break;
-                       if (!ferror(stdin))
-                               die("fgets returned NULL, not EOF, not error!");
-                       if (errno != EINTR)
-                               die("fgets: %s", strerror(errno));
-                       clearerr(stdin);
-                       continue;
-               }
-
-               if (line[0] == '-') {
-                       if (get_sha1_hex(line+1, sha1))
-                               die("expected edge sha1, got garbage:\n %s",
-                                   line+1);
-                       if (num_preferred_base++ < window)
-                               add_preferred_base(sha1);
-                       continue;
-               }
-               if (get_sha1_hex(line, sha1))
-                       die("expected sha1, got garbage:\n %s", line);
-               hash = name_hash(line+41);
-               add_preferred_base_object(line+41, hash);
-               add_object_entry(sha1, hash, 0);
+       if (!use_internal_rev_list)
+               read_object_list_from_stdin();
+       else {
+               rp_av[rp_ac] = NULL;
+               get_object_list(rp_ac, rp_av);
        }
+
        if (progress)
                fprintf(stderr, "Done counting %d objects.\n", nr_objects);
        sorted_by_sha = create_final_object_list();
index d3dd94d9ef7a50e156488ea5e9236d6d55f6e190..960db49859a286bf5f3515ee7c2bfe25fe44d09e 100644 (file)
@@ -19,7 +19,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len)
                memcpy(hex+2, de->d_name, 38);
                if (get_sha1_hex(hex, sha1))
                        continue;
-               if (!has_sha1_pack(sha1))
+               if (!has_sha1_pack(sha1, NULL))
                        continue;
                memcpy(pathname + len, de->d_name, 38);
                if (dryrun)
index 8fe8afbd0469c689cad111df6302508d352b6c29..1f3333da38c77a07840a8dfad052c301dbae9392 100644 (file)
@@ -7,6 +7,7 @@
 #include "tree-walk.h"
 #include "diff.h"
 #include "revision.h"
+#include "list-objects.h"
 #include "builtin.h"
 
 /* bits #0-15 in revision.h */
@@ -98,104 +99,24 @@ static void show_commit(struct commit *commit)
        commit->buffer = NULL;
 }
 
-static void process_blob(struct blob *blob,
-                        struct object_array *p,
-                        struct name_path *path,
-                        const char *name)
+static void show_object(struct object_array_entry *p)
 {
-       struct object *obj = &blob->object;
-
-       if (!revs.blob_objects)
-               return;
-       if (obj->flags & (UNINTERESTING | SEEN))
-               return;
-       obj->flags |= SEEN;
-       name = xstrdup(name);
-       add_object(obj, p, path, name);
-}
-
-static void process_tree(struct tree *tree,
-                        struct object_array *p,
-                        struct name_path *path,
-                        const char *name)
-{
-       struct object *obj = &tree->object;
-       struct tree_desc desc;
-       struct name_entry entry;
-       struct name_path me;
-
-       if (!revs.tree_objects)
-               return;
-       if (obj->flags & (UNINTERESTING | SEEN))
-               return;
-       if (parse_tree(tree) < 0)
-               die("bad tree object %s", sha1_to_hex(obj->sha1));
-       obj->flags |= SEEN;
-       name = xstrdup(name);
-       add_object(obj, p, path, name);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
-
-       desc.buf = tree->buffer;
-       desc.size = tree->size;
-
-       while (tree_entry(&desc, &entry)) {
-               if (S_ISDIR(entry.mode))
-                       process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
-               else
-                       process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+       /* An object with name "foo\n0000000..." can be used to
+        * confuse downstream git-pack-objects very badly.
+        */
+       const char *ep = strchr(p->name, '\n');
+       if (ep) {
+               printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
+                      (int) (ep - p->name),
+                      p->name);
        }
-       free(tree->buffer);
-       tree->buffer = NULL;
+       else
+               printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
 }
 
-static void show_commit_list(struct rev_info *revs)
+static void show_edge(struct commit *commit)
 {
-       int i;
-       struct commit *commit;
-       struct object_array objects = { 0, 0, NULL };
-
-       while ((commit = get_revision(revs)) != NULL) {
-               process_tree(commit->tree, &objects, NULL, "");
-               show_commit(commit);
-       }
-       for (i = 0; i < revs->pending.nr; i++) {
-               struct object_array_entry *pending = revs->pending.objects + i;
-               struct object *obj = pending->item;
-               const char *name = pending->name;
-               if (obj->flags & (UNINTERESTING | SEEN))
-                       continue;
-               if (obj->type == OBJ_TAG) {
-                       obj->flags |= SEEN;
-                       add_object_array(obj, name, &objects);
-                       continue;
-               }
-               if (obj->type == OBJ_TREE) {
-                       process_tree((struct tree *)obj, &objects, NULL, name);
-                       continue;
-               }
-               if (obj->type == OBJ_BLOB) {
-                       process_blob((struct blob *)obj, &objects, NULL, name);
-                       continue;
-               }
-               die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
-       }
-       for (i = 0; i < objects.nr; i++) {
-               struct object_array_entry *p = objects.objects + i;
-
-               /* An object with name "foo\n0000000..." can be used to
-                * confuse downstream git-pack-objects very badly.
-                */
-               const char *ep = strchr(p->name, '\n');
-               if (ep) {
-                       printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
-                              (int) (ep - p->name),
-                              p->name);
-               }
-               else
-                       printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
-       }
+       printf("-%s\n", sha1_to_hex(commit->object.sha1));
 }
 
 /*
@@ -276,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];
@@ -384,12 +276,12 @@ 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);
 
-       show_commit_list(&revs);
+       traverse_commit_list(&revs, show_commit, show_object);
 
        return 0;
 }
diff --git a/cache.h b/cache.h
index 8d099979d9a04231d73307c786d25bf412a3f22c..57db7c9b20aad5d14ab4e77fd0e338b98c446bcc 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -259,7 +259,7 @@ extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
 extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
 extern int move_temp_to_file(const char *tmpfile, const char *filename);
 
-extern int has_sha1_pack(const unsigned char *sha1);
+extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
 extern int has_sha1_file(const unsigned char *sha1);
 extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
 extern int legacy_loose_object(unsigned char *);
diff --git a/list-objects.c b/list-objects.c
new file mode 100644 (file)
index 0000000..f1fa21c
--- /dev/null
@@ -0,0 +1,140 @@
+#include "cache.h"
+#include "tag.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
+#include "diff.h"
+#include "tree-walk.h"
+#include "revision.h"
+#include "list-objects.h"
+
+static void process_blob(struct rev_info *revs,
+                        struct blob *blob,
+                        struct object_array *p,
+                        struct name_path *path,
+                        const char *name)
+{
+       struct object *obj = &blob->object;
+
+       if (!revs->blob_objects)
+               return;
+       if (obj->flags & (UNINTERESTING | SEEN))
+               return;
+       obj->flags |= SEEN;
+       name = xstrdup(name);
+       add_object(obj, p, path, name);
+}
+
+static void process_tree(struct rev_info *revs,
+                        struct tree *tree,
+                        struct object_array *p,
+                        struct name_path *path,
+                        const char *name)
+{
+       struct object *obj = &tree->object;
+       struct tree_desc desc;
+       struct name_entry entry;
+       struct name_path me;
+
+       if (!revs->tree_objects)
+               return;
+       if (obj->flags & (UNINTERESTING | SEEN))
+               return;
+       if (parse_tree(tree) < 0)
+               die("bad tree object %s", sha1_to_hex(obj->sha1));
+       obj->flags |= SEEN;
+       name = xstrdup(name);
+       add_object(obj, p, path, name);
+       me.up = path;
+       me.elem = name;
+       me.elem_len = strlen(name);
+
+       desc.buf = tree->buffer;
+       desc.size = tree->size;
+
+       while (tree_entry(&desc, &entry)) {
+               if (S_ISDIR(entry.mode))
+                       process_tree(revs,
+                                    lookup_tree(entry.sha1),
+                                    p, &me, entry.path);
+               else
+                       process_blob(revs,
+                                    lookup_blob(entry.sha1),
+                                    p, &me, entry.path);
+       }
+       free(tree->buffer);
+       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 *))
+{
+       int i;
+       struct commit *commit;
+       struct object_array objects = { 0, 0, NULL };
+
+       while ((commit = get_revision(revs)) != NULL) {
+               process_tree(revs, commit->tree, &objects, NULL, "");
+               show_commit(commit);
+       }
+       for (i = 0; i < revs->pending.nr; i++) {
+               struct object_array_entry *pending = revs->pending.objects + i;
+               struct object *obj = pending->item;
+               const char *name = pending->name;
+               if (obj->flags & (UNINTERESTING | SEEN))
+                       continue;
+               if (obj->type == OBJ_TAG) {
+                       obj->flags |= SEEN;
+                       add_object_array(obj, name, &objects);
+                       continue;
+               }
+               if (obj->type == OBJ_TREE) {
+                       process_tree(revs, (struct tree *)obj, &objects,
+                                    NULL, name);
+                       continue;
+               }
+               if (obj->type == OBJ_BLOB) {
+                       process_blob(revs, (struct blob *)obj, &objects,
+                                    NULL, name);
+                       continue;
+               }
+               die("unknown pending object %s (%s)",
+                   sha1_to_hex(obj->sha1), name);
+       }
+       for (i = 0; i < objects.nr; i++)
+               show_object(&objects.objects[i]);
+}
diff --git a/list-objects.h b/list-objects.h
new file mode 100644 (file)
index 0000000..0f41391
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef LIST_OBJECTS_H
+#define LIST_OBJECTS_H
+
+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
index db01682750a4dfa820ea3f0e4a99e306aa6b075a..6a2539b623512917479be3e6601ee8b8bef4953d 100644 (file)
@@ -416,7 +416,8 @@ static void limit_list(struct rev_info *revs)
 
                if (revs->max_age != -1 && (commit->date < revs->max_age))
                        obj->flags |= UNINTERESTING;
-               if (revs->unpacked && has_sha1_pack(obj->sha1))
+               if (revs->unpacked &&
+                   has_sha1_pack(obj->sha1, revs->ignore_packed))
                        obj->flags |= UNINTERESTING;
                add_parents_to_list(revs, commit, &list);
                if (obj->flags & UNINTERESTING) {
@@ -671,6 +672,16 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
        return 0;
 }
 
+static void add_ignore_packed(struct rev_info *revs, const char *name)
+{
+       int num = ++revs->num_ignore_packed;
+
+       revs->ignore_packed = xrealloc(revs->ignore_packed,
+                                      sizeof(const char **) * (num + 1));
+       revs->ignore_packed[num-1] = name;
+       revs->ignore_packed[num] = NULL;
+}
+
 /*
  * Parse revision information, filling in the "rev_info" structure,
  * and removing the used arguments from the argument list.
@@ -811,6 +822,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!strcmp(arg, "--unpacked")) {
                                revs->unpacked = 1;
+                               free(revs->ignore_packed);
+                               revs->ignore_packed = NULL;
+                               revs->num_ignore_packed = 0;
+                               continue;
+                       }
+                       if (!strncmp(arg, "--unpacked=", 11)) {
+                               revs->unpacked = 1;
+                               add_ignore_packed(revs, arg+11);
                                continue;
                        }
                        if (!strcmp(arg, "-r")) {
@@ -1057,7 +1076,8 @@ struct commit *get_revision(struct rev_info *revs)
                 */
                if (!revs->limited) {
                        if ((revs->unpacked &&
-                            has_sha1_pack(commit->object.sha1)) ||
+                            has_sha1_pack(commit->object.sha1,
+                                          revs->ignore_packed)) ||
                            (revs->max_age != -1 &&
                             (commit->date < revs->max_age)))
                                continue;
index c1f71afe6fa71075b64df03c1e9616f50325d29e..a5c35d05cbd6bceb12248dff0b1e5c3f3433aeae 100644 (file)
@@ -38,7 +38,7 @@ struct rev_info {
                        blob_objects:1,
                        edge_hint:1,
                        limited:1,
-                       unpacked:1,
+                       unpacked:1, /* see also ignore_packed below */
                        boundary:1,
                        parents:1;
 
@@ -57,6 +57,10 @@ struct rev_info {
        unsigned int    shown_one:1,
                        abbrev_commit:1,
                        relative_date:1;
+
+       const char **ignore_packed; /* pretend objects in these are unpacked */
+       int num_ignore_packed;
+
        unsigned int    abbrev;
        enum cmit_fmt   commit_format;
        struct log_info *loginfo;
index b64b92de4e7a6c59edfb3e60ff1440a98cacdeea..b89edb9515aa38c2c404367aa28ec5531fcc7de1 100644 (file)
@@ -1217,12 +1217,20 @@ int find_pack_entry_one(const unsigned char *sha1,
        return 0;
 }
 
-static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
+static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
 {
        struct packed_git *p;
        prepare_packed_git();
 
        for (p = packed_git; p; p = p->next) {
+               if (ignore_packed) {
+                       const char **ig;
+                       for (ig = ignore_packed; *ig; ig++)
+                               if (!strcmp(p->pack_name, *ig))
+                                       break;
+                       if (*ig)
+                               continue;
+               }
                if (find_pack_entry_one(sha1, e, p))
                        return 1;
        }
@@ -1255,10 +1263,10 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
        if (!map) {
                struct pack_entry e;
 
-               if (find_pack_entry(sha1, &e))
+               if (find_pack_entry(sha1, &e, NULL))
                        return packed_object_info(&e, type, sizep);
                reprepare_packed_git();
-               if (find_pack_entry(sha1, &e))
+               if (find_pack_entry(sha1, &e, NULL))
                        return packed_object_info(&e, type, sizep);
                return error("unable to find %s", sha1_to_hex(sha1));
        }
@@ -1281,7 +1289,7 @@ static void *read_packed_sha1(const unsigned char *sha1, char *type, unsigned lo
 {
        struct pack_entry e;
 
-       if (!find_pack_entry(sha1, &e)) {
+       if (!find_pack_entry(sha1, &e, NULL)) {
                error("cannot read sha1_file for %s", sha1_to_hex(sha1));
                return NULL;
        }
@@ -1294,7 +1302,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
        void *map, *buf;
        struct pack_entry e;
 
-       if (find_pack_entry(sha1, &e))
+       if (find_pack_entry(sha1, &e, NULL))
                return read_packed_sha1(sha1, type, size);
        map = map_sha1_file(sha1, &mapsize);
        if (map) {
@@ -1303,7 +1311,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
                return buf;
        }
        reprepare_packed_git();
-       if (find_pack_entry(sha1, &e))
+       if (find_pack_entry(sha1, &e, NULL))
                return read_packed_sha1(sha1, type, size);
        return NULL;
 }
@@ -1735,10 +1743,10 @@ int has_pack_file(const unsigned char *sha1)
        return 1;
 }
 
-int has_sha1_pack(const unsigned char *sha1)
+int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed)
 {
        struct pack_entry e;
-       return find_pack_entry(sha1, &e);
+       return find_pack_entry(sha1, &e, ignore_packed);
 }
 
 int has_sha1_file(const unsigned char *sha1)
@@ -1746,7 +1754,7 @@ int has_sha1_file(const unsigned char *sha1)
        struct stat st;
        struct pack_entry e;
 
-       if (find_pack_entry(sha1, &e))
+       if (find_pack_entry(sha1, &e, NULL))
                return 1;
        return find_sha1_file(sha1, &st) ? 1 : 0;
 }