diff options
Diffstat (limited to 'shallow.c')
-rw-r--r-- | shallow.c | 180 |
1 files changed, 114 insertions, 66 deletions
@@ -1,6 +1,8 @@ #include "cache.h" +#include "repository.h" #include "tempfile.h" #include "lockfile.h" +#include "object-store.h" #include "commit.h" #include "tag.h" #include "pkt-line.h" @@ -12,68 +14,79 @@ #include "commit-slab.h" #include "revision.h" #include "list-objects.h" +#include "commit-slab.h" +#include "repository.h" +#include "commit-reach.h" -static int is_shallow = -1; -static struct stat_validity shallow_stat; -static char *alternate_shallow_file; - -void set_alternate_shallow_file(const char *path, int override) +void set_alternate_shallow_file(struct repository *r, const char *path, int override) { - if (is_shallow != -1) + if (r->parsed_objects->is_shallow != -1) BUG("is_repository_shallow must not be called before set_alternate_shallow_file"); - if (alternate_shallow_file && !override) + if (r->parsed_objects->alternate_shallow_file && !override) return; - free(alternate_shallow_file); - alternate_shallow_file = xstrdup_or_null(path); + free(r->parsed_objects->alternate_shallow_file); + r->parsed_objects->alternate_shallow_file = xstrdup_or_null(path); } -int register_shallow(const struct object_id *oid) +int register_shallow(struct repository *r, const struct object_id *oid) { struct commit_graft *graft = xmalloc(sizeof(struct commit_graft)); - struct commit *commit = lookup_commit(oid); + struct commit *commit = lookup_commit(the_repository, oid); oidcpy(&graft->oid, oid); graft->nr_parent = -1; if (commit && commit->object.parsed) commit->parents = NULL; - return register_commit_graft(graft, 0); + return register_commit_graft(r, graft, 0); } -int is_repository_shallow(void) +int is_repository_shallow(struct repository *r) { + /* + * NEEDSWORK: This function updates + * r->parsed_objects->{is_shallow,shallow_stat} as a side effect but + * there is no corresponding function to clear them when the shallow + * file is updated. + */ + FILE *fp; char buf[1024]; - const char *path = alternate_shallow_file; + const char *path = r->parsed_objects->alternate_shallow_file; - if (is_shallow >= 0) - return is_shallow; + if (r->parsed_objects->is_shallow >= 0) + return r->parsed_objects->is_shallow; if (!path) - path = git_path_shallow(); + path = git_path_shallow(r); /* * fetch-pack sets '--shallow-file ""' as an indicator that no * shallow file should be used. We could just open it and it * will likely fail. But let's do an explicit check instead. */ if (!*path || (fp = fopen(path, "r")) == NULL) { - stat_validity_clear(&shallow_stat); - is_shallow = 0; - return is_shallow; + stat_validity_clear(r->parsed_objects->shallow_stat); + r->parsed_objects->is_shallow = 0; + return r->parsed_objects->is_shallow; } - stat_validity_update(&shallow_stat, fileno(fp)); - is_shallow = 1; + stat_validity_update(r->parsed_objects->shallow_stat, fileno(fp)); + r->parsed_objects->is_shallow = 1; while (fgets(buf, sizeof(buf), fp)) { struct object_id oid; if (get_oid_hex(buf, &oid)) die("bad shallow line: %s", buf); - register_shallow(&oid); + register_shallow(r, &oid); } fclose(fp); - return is_shallow; + return r->parsed_objects->is_shallow; } +/* + * TODO: use "int" elemtype instead of "int *" when/if commit-slab + * supports a "valid" flag. + */ +define_commit_slab(commit_depth, int *); struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag) { @@ -82,32 +95,38 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth, struct object_array stack = OBJECT_ARRAY_INIT; struct commit *commit = NULL; struct commit_graft *graft; + struct commit_depth depths; + init_commit_depth(&depths); while (commit || i < heads->nr || stack.nr) { struct commit_list *p; if (!commit) { if (i < heads->nr) { + int **depth_slot; commit = (struct commit *) - deref_tag(heads->objects[i++].item, NULL, 0); + deref_tag(the_repository, + heads->objects[i++].item, + NULL, 0); if (!commit || commit->object.type != OBJ_COMMIT) { commit = NULL; continue; } - if (!commit->util) - commit->util = xmalloc(sizeof(int)); - *(int *)commit->util = 0; + depth_slot = commit_depth_at(&depths, commit); + if (!*depth_slot) + *depth_slot = xmalloc(sizeof(int)); + **depth_slot = 0; cur_depth = 0; } else { commit = (struct commit *) object_array_pop(&stack); - cur_depth = *(int *)commit->util; + cur_depth = **commit_depth_at(&depths, commit); } } parse_commit_or_die(commit); cur_depth++; if ((depth != INFINITE_DEPTH && cur_depth >= depth) || - (is_repository_shallow() && !commit->parents && - (graft = lookup_commit_graft(&commit->object.oid)) != NULL && + (is_repository_shallow(the_repository) && !commit->parents && + (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL && graft->nr_parent < 0)) { commit_list_insert(commit, &result); commit->object.flags |= shallow_flag; @@ -116,25 +135,31 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth, } commit->object.flags |= not_shallow_flag; for (p = commit->parents, commit = NULL; p; p = p->next) { - if (!p->item->util) { - int *pointer = xmalloc(sizeof(int)); - p->item->util = pointer; - *pointer = cur_depth; + int **depth_slot = commit_depth_at(&depths, p->item); + if (!*depth_slot) { + *depth_slot = xmalloc(sizeof(int)); + **depth_slot = cur_depth; } else { - int *pointer = p->item->util; - if (cur_depth >= *pointer) + if (cur_depth >= **depth_slot) continue; - *pointer = cur_depth; + **depth_slot = cur_depth; } if (p->next) add_object_array(&p->item->object, NULL, &stack); else { commit = p->item; - cur_depth = *(int *)commit->util; + cur_depth = **commit_depth_at(&depths, commit); } } } + for (i = 0; i < depths.slab_count; i++) { + int j; + + for (j = 0; j < depths.slab_size; j++) + free(depths.slab[i][j]); + } + clear_commit_depth(&depths); return result; } @@ -165,9 +190,9 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, */ clear_object_flags(both_flags); - is_repository_shallow(); /* make sure shallows are read */ + is_repository_shallow(the_repository); /* make sure shallows are read */ - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; setup_revisions(ac, av, &revs, NULL); @@ -175,6 +200,9 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, die("revision walk setup failed"); traverse_commit_list(&revs, show_commit, NULL, ¬_shallow_list); + if (!not_shallow_list) + die("no commits selected for shallow requests"); + /* Mark all reachable commits as NOT_SHALLOW */ for (p = not_shallow_list; p; p = p->next) p->item->object.flags |= not_shallow_flag; @@ -215,17 +243,18 @@ struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, return result; } -static void check_shallow_file_for_update(void) +static void check_shallow_file_for_update(struct repository *r) { - if (is_shallow == -1) + if (r->parsed_objects->is_shallow == -1) BUG("shallow must be initialized by now"); - if (!stat_validity_check(&shallow_stat, git_path_shallow())) + if (!stat_validity_check(r->parsed_objects->shallow_stat, git_path_shallow(the_repository))) die("shallow file has changed since we read it"); } #define SEEN_ONLY 1 #define VERBOSE 2 +#define QUICK 4 struct write_shallow_data { struct strbuf *out; @@ -240,8 +269,11 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) const char *hex = oid_to_hex(&graft->oid); if (graft->nr_parent != -1) return 0; - if (data->flags & SEEN_ONLY) { - struct commit *c = lookup_commit(&graft->oid); + if (data->flags & QUICK) { + if (!has_object_file(&graft->oid)) + return 0; + } else if (data->flags & SEEN_ONLY) { + struct commit *c = lookup_commit(the_repository, &graft->oid); if (!c || !(c->object.flags & SEEN)) { if (data->flags & VERBOSE) printf("Removing %s from .git/shallow\n", @@ -315,9 +347,10 @@ void setup_alternate_shallow(struct lock_file *shallow_lock, struct strbuf sb = STRBUF_INIT; int fd; - fd = hold_lock_file_for_update(shallow_lock, git_path_shallow(), + fd = hold_lock_file_for_update(shallow_lock, + git_path_shallow(the_repository), LOCK_DIE_ON_ERROR); - check_shallow_file_for_update(); + check_shallow_file_for_update(the_repository); if (write_shallow_commits(&sb, 0, extra)) { if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", @@ -342,36 +375,44 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c void advertise_shallow_grafts(int fd) { - if (!is_repository_shallow()) + if (!is_repository_shallow(the_repository)) return; for_each_commit_graft(advertise_shallow_grafts_cb, &fd); } /* * mark_reachable_objects() should have been run prior to this and all - * reachable commits marked as "SEEN". + * reachable commits marked as "SEEN", except when quick_prune is non-zero, + * in which case lines are excised from the shallow file if they refer to + * commits that do not exist (any longer). */ -void prune_shallow(int show_only) +void prune_shallow(unsigned options) { struct lock_file shallow_lock = LOCK_INIT; struct strbuf sb = STRBUF_INIT; + unsigned flags = SEEN_ONLY; int fd; - if (show_only) { - write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE); + if (options & PRUNE_QUICK) + flags |= QUICK; + + if (options & PRUNE_SHOW_ONLY) { + flags |= VERBOSE; + write_shallow_commits_1(&sb, 0, NULL, flags); strbuf_release(&sb); return; } - fd = hold_lock_file_for_update(&shallow_lock, git_path_shallow(), + fd = hold_lock_file_for_update(&shallow_lock, + git_path_shallow(the_repository), LOCK_DIE_ON_ERROR); - check_shallow_file_for_update(); - if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { + check_shallow_file_for_update(the_repository); + if (write_shallow_commits_1(&sb, 0, NULL, flags)) { if (write_in_full(fd, sb.buf, sb.len) < 0) die_errno("failed to write to %s", get_lock_file_path(&shallow_lock)); commit_lock_file(&shallow_lock); } else { - unlink(git_path_shallow()); + unlink(git_path_shallow(the_repository)); rollback_lock_file(&shallow_lock); } strbuf_release(&sb); @@ -396,7 +437,8 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) for (i = 0; i < sa->nr; i++) { if (has_object_file(sa->oid + i)) { struct commit_graft *graft; - graft = lookup_commit_graft(&sa->oid[i]); + graft = lookup_commit_graft(the_repository, + &sa->oid[i]); if (graft && graft->nr_parent < 0) continue; info->ours[info->nr_ours++] = i; @@ -471,7 +513,8 @@ static void paint_down(struct paint_info *info, const struct object_id *oid, struct commit_list *head = NULL; int bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32); size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr); - struct commit *c = lookup_commit_reference_gently(oid, 1); + struct commit *c = lookup_commit_reference_gently(the_repository, oid, + 1); uint32_t *tmp; /* to be freed before return */ uint32_t *bitmap; @@ -533,7 +576,8 @@ static void paint_down(struct paint_info *info, const struct object_id *oid, static int mark_uninteresting(const char *refname, const struct object_id *oid, int flags, void *cb_data) { - struct commit *commit = lookup_commit_reference_gently(oid, 1); + struct commit *commit = lookup_commit_reference_gently(the_repository, + oid, 1); if (!commit) return 0; commit->object.flags |= UNINTERESTING; @@ -601,7 +645,8 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, /* Mark potential bottoms so we won't go out of bound */ for (i = 0; i < nr_shallow; i++) { - struct commit *c = lookup_commit(&oid[shallow[i]]); + struct commit *c = lookup_commit(the_repository, + &oid[shallow[i]]); c->object.flags |= BOTTOM; } @@ -612,7 +657,8 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, int bitmap_size = DIV_ROUND_UP(pi.nr_bits, 32) * sizeof(uint32_t); memset(used, 0, sizeof(*used) * info->shallow->nr); for (i = 0; i < nr_shallow; i++) { - const struct commit *c = lookup_commit(&oid[shallow[i]]); + const struct commit *c = lookup_commit(the_repository, + &oid[shallow[i]]); uint32_t **map = ref_bitmap_at(&pi.ref_bitmap, c); if (*map) used[shallow[i]] = xmemdupz(*map, bitmap_size); @@ -643,7 +689,8 @@ static int add_ref(const char *refname, const struct object_id *oid, { struct commit_array *ca = cb_data; ALLOC_GROW(ca->commits, ca->nr + 1, ca->alloc); - ca->commits[ca->nr] = lookup_commit_reference_gently(oid, 1); + ca->commits[ca->nr] = lookup_commit_reference_gently(the_repository, + oid, 1); if (ca->commits[ca->nr]) ca->nr++; return 0; @@ -681,7 +728,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - c = lookup_commit(&oid[info->theirs[i]]); + c = lookup_commit(the_repository, &oid[info->theirs[i]]); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -702,7 +749,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_ours; i++) { if (i != dst) info->ours[dst] = info->ours[i]; - c = lookup_commit(&oid[info->ours[i]]); + c = lookup_commit(the_repository, &oid[info->ours[i]]); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -724,7 +771,8 @@ static void post_assign_shallow(struct shallow_info *info, int delayed_reachability_test(struct shallow_info *si, int c) { if (si->need_reachability_test[c]) { - struct commit *commit = lookup_commit(&si->shallow->oid[c]); + struct commit *commit = lookup_commit(the_repository, + &si->shallow->oid[c]); if (!si->commits) { struct commit_array ca; |