From 8d1d8f83b5d918c6071b606e321de9c31fed9e68 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 6 Sep 2006 01:42:23 -0700 Subject: [PATCH] pack-objects: further work on internal rev-list logic. 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 --- builtin-pack-objects.c | 99 +++++++++++++++++------------------------- builtin-rev-list.c | 36 +++------------ list-objects.c | 33 ++++++++++++++ list-objects.h | 10 +++-- 4 files changed, 85 insertions(+), 93 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index b6e59609e8..753dd9a414 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -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); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 0900737f40..1f3333da38 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -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); diff --git a/list-objects.c b/list-objects.c index adaf9979e6..f1fa21c397 100644 --- a/list-objects.c +++ b/list-objects.c @@ -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 *)) diff --git a/list-objects.h b/list-objects.h index 8a5fae66ec..0f41391ecc 100644 --- a/list-objects.h +++ b/list-objects.h @@ -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