int fsck_finish(struct fsck_options *options) { int ret = 0; struct oidset_iter iter; const struct object_id *oid; oidset_iter_init(&gitmodules_found, &iter); while ((oid = oidset_iter_next(&iter))) { struct blob *blob; enum object_type type; unsigned long size; char *buf; if (oidset_contains(&gitmodules_done, oid)) continue; blob = lookup_blob(oid); if (!blob) { struct object *obj = lookup_unknown_object(oid->hash); ret |= report(options, obj, FSCK_MSG_GITMODULES_BLOB, "non-blob found at .gitmodules"); continue; } buf = read_object_file(oid, &type, &size); if (!buf) { if (is_promisor_object(&blob->object.oid)) continue; ret |= report(options, &blob->object, FSCK_MSG_GITMODULES_MISSING, "unable to read .gitmodules blob"); continue; } if (type == OBJ_BLOB) ret |= fsck_blob(blob, buf, size, options); else ret |= report(options, &blob->object, FSCK_MSG_GITMODULES_BLOB, "non-blob found at .gitmodules"); free(buf); } oidset_clear(&gitmodules_found); oidset_clear(&gitmodules_done); return ret; }
int cmd_rev_list(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct rev_list_info info; int i; int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; int use_bitmap_index = 0; const char *show_progress = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage(rev_list_usage); git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = DEFAULT_ABBREV; revs.commit_format = CMIT_FMT_UNSPECIFIED; /* * Scan the argument list before invoking setup_revisions(), so that we * know if fetch_if_missing needs to be set to 0. * * "--exclude-promisor-objects" acts as a pre-filter on missing objects * by not crossing the boundary from realized objects to promisor * objects. * * Let "--missing" to conditionally set fetch_if_missing. */ for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--exclude-promisor-objects")) { fetch_if_missing = 0; revs.exclude_promisor_objects = 1; break; } } for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (skip_prefix(arg, "--missing=", &arg)) { if (revs.exclude_promisor_objects) die(_("cannot combine --exclude-promisor-objects and --missing")); if (parse_missing_action_value(arg)) break; } } argc = setup_revisions(argc, argv, &revs, NULL); memset(&info, 0, sizeof(info)); info.revs = &revs; if (revs.bisect) bisect_list = 1; if (revs.diffopt.flags.quick) info.flags |= REV_LIST_QUIET; for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--header")) { revs.verbose_header = 1; continue; } if (!strcmp(arg, "--timestamp")) { info.show_timestamp = 1; continue; } if (!strcmp(arg, "--bisect")) { bisect_list = 1; continue; } if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; info.flags |= BISECT_SHOW_ALL; revs.show_decorations = 1; continue; } if (!strcmp(arg, "--bisect-vars")) { bisect_list = 1; bisect_show_vars = 1; continue; } if (!strcmp(arg, "--use-bitmap-index")) { use_bitmap_index = 1; continue; } if (!strcmp(arg, "--test-bitmap")) { test_bitmap_walk(&revs); return 0; } if (skip_prefix(arg, "--progress=", &arg)) { show_progress = arg; continue; } if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) { parse_list_objects_filter(&filter_options, arg); if (filter_options.choice && !revs.blob_objects) die(_("object filtering requires --objects")); if (filter_options.choice == LOFC_SPARSE_OID && !filter_options.sparse_oid_value) die(_("invalid sparse value '%s'"), filter_options.filter_spec); continue; } if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) { list_objects_filter_set_no_filter(&filter_options); continue; } if (!strcmp(arg, "--filter-print-omitted")) { arg_print_omitted = 1; continue; } if (!strcmp(arg, "--exclude-promisor-objects")) continue; /* already handled above */ if (skip_prefix(arg, "--missing=", &arg)) continue; /* already handled above */ usage(rev_list_usage); } if (revs.commit_format != CMIT_FMT_UNSPECIFIED) { /* The command line has a --pretty */ info.hdr_termination = '\n'; if (revs.commit_format == CMIT_FMT_ONELINE) info.header_prefix = ""; else info.header_prefix = "commit "; } else if (revs.verbose_header) /* Only --header was specified */ revs.commit_format = CMIT_FMT_RAW; if ((!revs.commits && reflog_walk_empty(revs.reflog_info) && (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) && !revs.pending.nr) && !revs.rev_input_given && !revs.read_from_stdin) || revs.diff) usage(rev_list_usage); if (revs.show_notes) die(_("rev-list does not support display of notes")); if (filter_options.choice && use_bitmap_index) die(_("cannot combine --use-bitmap-index with object filtering")); save_commit_buffer = (revs.verbose_header || revs.grep_filter.pattern_list || revs.grep_filter.header_list); if (bisect_list) revs.limited = 1; if (show_progress) progress = start_delayed_progress(show_progress, 0); if (use_bitmap_index && !revs.prune) { if (revs.count && !revs.left_right && !revs.cherry_mark) { uint32_t commit_count; int max_count = revs.max_count; struct bitmap_index *bitmap_git; if ((bitmap_git = prepare_bitmap_walk(&revs))) { count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL); if (max_count >= 0 && max_count < commit_count) commit_count = max_count; printf("%d\n", commit_count); free_bitmap_index(bitmap_git); return 0; } } else if (revs.max_count < 0 && revs.tag_objects && revs.tree_objects && revs.blob_objects) { struct bitmap_index *bitmap_git; if ((bitmap_git = prepare_bitmap_walk(&revs))) { traverse_bitmap_commit_list(bitmap_git, &show_object_fast); free_bitmap_index(bitmap_git); return 0; } } } if (prepare_revision_walk(&revs)) die("revision walk setup failed"); if (revs.tree_objects) mark_edges_uninteresting(&revs, show_edge); if (bisect_list) { int reaches, all; find_bisection(&revs.commits, &reaches, &all, bisect_find_all); if (bisect_show_vars) return show_bisect_vars(&info, reaches, all); } if (arg_print_omitted) oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE); if (arg_missing_action == MA_PRINT) oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE); traverse_commit_list_filtered( &filter_options, &revs, show_commit, show_object, &info, (arg_print_omitted ? &omitted_objects : NULL)); if (arg_print_omitted) { struct oidset_iter iter; struct object_id *oid; oidset_iter_init(&omitted_objects, &iter); while ((oid = oidset_iter_next(&iter))) printf("~%s\n", oid_to_hex(oid)); oidset_clear(&omitted_objects); } if (arg_missing_action == MA_PRINT) { struct oidset_iter iter; struct object_id *oid; oidset_iter_init(&missing_objects, &iter); while ((oid = oidset_iter_next(&iter))) printf("?%s\n", oid_to_hex(oid)); oidset_clear(&missing_objects); } stop_progress(&progress); if (revs.count) { if (revs.left_right && revs.cherry_mark) printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same); else if (revs.left_right) printf("%d\t%d\n", revs.count_left, revs.count_right); else if (revs.cherry_mark) printf("%d\t%d\n", revs.count_left + revs.count_right, revs.count_same); else printf("%d\n", revs.count_left + revs.count_right); } return 0; }
/* * Mark recent commits available locally and reachable from a local ref as * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as * COMMON_REF (otherwise, we are not planning to participate in negotiation, and * thus do not need COMMON_REF marks). * * The cutoff time for recency is determined by this heuristic: it is the * earliest commit time of the objects in refs that are commits and that we know * the commit time of. */ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator, struct fetch_pack_args *args, struct ref **refs) { struct ref *ref; int old_save_commit_buffer = save_commit_buffer; timestamp_t cutoff = 0; struct oidset loose_oid_set = OIDSET_INIT; int use_oidset = 0; struct loose_object_iter iter = {&loose_oid_set, *refs}; /* Enumerate all loose objects or know refs are not so many. */ use_oidset = !for_each_loose_object(add_loose_objects_to_set, &iter, 0); save_commit_buffer = 0; for (ref = *refs; ref; ref = ref->next) { struct object *o; unsigned int flags = OBJECT_INFO_QUICK; if (use_oidset && !oidset_contains(&loose_oid_set, &ref->old_oid)) { /* * I know this does not exist in the loose form, * so check if it exists in a non-loose form. */ flags |= OBJECT_INFO_IGNORE_LOOSE; } if (!has_object_file_with_flags(&ref->old_oid, flags)) continue; o = parse_object(the_repository, &ref->old_oid); if (!o) continue; /* We already have it -- which may mean that we were * in sync with the other side at some time after * that (it is OK if we guess wrong here). */ if (o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!cutoff || cutoff < commit->date) cutoff = commit->date; } } oidset_clear(&loose_oid_set); if (!args->deepen) { for_each_ref(mark_complete_oid, NULL); for_each_cached_alternate(NULL, mark_alternate_complete); commit_list_sort_by_date(&complete); if (cutoff) mark_recent_complete_commits(args, cutoff); } /* * Mark all complete remote refs as common refs. * Don't mark them common yet; the server has to be told so first. */ for (ref = *refs; ref; ref = ref->next) { struct object *o = deref_tag(the_repository, lookup_object(the_repository, ref->old_oid.hash), NULL, 0); if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) continue; negotiator->known_common(negotiator, (struct commit *)o); } save_commit_buffer = old_save_commit_buffer; }
static void filter_refs(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *newlist = NULL; struct ref **newtail = &newlist; struct ref *unmatched = NULL; struct ref *ref, *next; struct oidset tip_oids = OIDSET_INIT; int i; int strict = !(allow_unadvertised_object_request & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)); i = 0; for (ref = *refs; ref; ref = next) { int keep = 0; next = ref->next; if (starts_with(ref->name, "refs/") && check_refname_format(ref->name, 0)) ; /* trash */ else { while (i < nr_sought) { int cmp = strcmp(ref->name, sought[i]->name); if (cmp < 0) break; /* definitely do not have it */ else if (cmp == 0) { keep = 1; /* definitely have it */ sought[i]->match_status = REF_MATCHED; } i++; } if (!keep && args->fetch_all && (!args->deepen || !starts_with(ref->name, "refs/tags/"))) keep = 1; } if (keep) { *newtail = ref; ref->next = NULL; newtail = &ref->next; } else { ref->next = unmatched; unmatched = ref; } } if (strict) { for (i = 0; i < nr_sought; i++) { ref = sought[i]; if (!is_unmatched_ref(ref)) continue; add_refs_to_oidset(&tip_oids, unmatched); add_refs_to_oidset(&tip_oids, newlist); break; } } /* Append unmatched requests to the list */ for (i = 0; i < nr_sought; i++) { ref = sought[i]; if (!is_unmatched_ref(ref)) continue; if (!strict || oidset_contains(&tip_oids, &ref->old_oid)) { ref->match_status = REF_MATCHED; *newtail = copy_ref(ref); newtail = &(*newtail)->next; } else { ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; } } oidset_clear(&tip_oids); for (ref = unmatched; ref; ref = next) { next = ref->next; free(ref); } *refs = newlist; }
static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, int fd[2], const struct ref *orig_ref, struct ref **sought, int nr_sought, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; struct packet_reader reader; int in_vain = 0; int haves_to_send = INITIAL_FLUSH; struct fetch_negotiator negotiator; fetch_negotiator_init(&negotiator, negotiation_algorithm); packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE); while (state != FETCH_DONE) { switch (state) { case FETCH_CHECK_LOCAL: sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); /* v2 supports these by default */ allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; use_sideband = 2; if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; /* Filter 'ref' by 'sought' and those that aren't local */ if (!args->no_dependents) { mark_complete_and_common_ref(&negotiator, args, &ref); filter_refs(args, &ref, sought, nr_sought); if (everything_local(args, &ref)) state = FETCH_DONE; else state = FETCH_SEND_REQUEST; mark_tips(&negotiator, args->negotiation_tips); for_each_cached_alternate(&negotiator, insert_one_alternate_object); } else { filter_refs(args, &ref, sought, nr_sought); state = FETCH_SEND_REQUEST; } break; case FETCH_SEND_REQUEST: if (send_fetch_request(&negotiator, fd[1], args, ref, &common, &haves_to_send, &in_vain)) state = FETCH_GET_PACK; else state = FETCH_PROCESS_ACKS; break; case FETCH_PROCESS_ACKS: /* Process ACKs/NAKs */ switch (process_acks(&negotiator, &reader, &common)) { case 2: state = FETCH_GET_PACK; break; case 1: in_vain = 0; /* fallthrough */ default: state = FETCH_SEND_REQUEST; break; } break; case FETCH_GET_PACK: /* Check for shallow-info section */ if (process_section_header(&reader, "shallow-info", 1)) receive_shallow_info(args, &reader); if (process_section_header(&reader, "wanted-refs", 1)) receive_wanted_refs(&reader, sought, nr_sought); /* get the pack */ process_section_header(&reader, "packfile", 0); if (get_pack(args, fd, pack_lockfile)) die(_("git fetch-pack: fetch failed.")); state = FETCH_DONE; break; case FETCH_DONE: continue; } } negotiator.release(&negotiator); oidset_clear(&common); return ref; }
static int everything_local(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *ref; int retval; int old_save_commit_buffer = save_commit_buffer; timestamp_t cutoff = 0; struct oidset loose_oid_set = OIDSET_INIT; int use_oidset = 0; struct loose_object_iter iter = {&loose_oid_set, *refs}; /* Enumerate all loose objects or know refs are not so many. */ use_oidset = !for_each_loose_object(add_loose_objects_to_set, &iter, 0); save_commit_buffer = 0; for (ref = *refs; ref; ref = ref->next) { struct object *o; unsigned int flags = OBJECT_INFO_QUICK; if (use_oidset && !oidset_contains(&loose_oid_set, &ref->old_oid)) { /* * I know this does not exist in the loose form, * so check if it exists in a non-loose form. */ flags |= OBJECT_INFO_IGNORE_LOOSE; } if (!has_object_file_with_flags(&ref->old_oid, flags)) continue; o = parse_object(&ref->old_oid); if (!o) continue; /* We already have it -- which may mean that we were * in sync with the other side at some time after * that (it is OK if we guess wrong here). */ if (o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; if (!cutoff || cutoff < commit->date) cutoff = commit->date; } } oidset_clear(&loose_oid_set); if (!args->no_dependents) { if (!args->deepen) { for_each_ref(mark_complete_oid, NULL); for_each_cached_alternate(mark_alternate_complete); commit_list_sort_by_date(&complete); if (cutoff) mark_recent_complete_commits(args, cutoff); } /* * Mark all complete remote refs as common refs. * Don't mark them common yet; the server has to be told so first. */ for (ref = *refs; ref; ref = ref->next) { struct object *o = deref_tag(lookup_object(ref->old_oid.hash), NULL, 0); if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) continue; if (!(o->flags & SEEN)) { rev_list_push((struct commit *)o, COMMON_REF | SEEN); mark_common((struct commit *)o, 1, 1); } } } filter_refs(args, refs, sought, nr_sought); for (retval = 1, ref = *refs; ref ; ref = ref->next) { const struct object_id *remote = &ref->old_oid; struct object *o; o = lookup_object(remote->hash); if (!o || !(o->flags & COMPLETE)) { retval = 0; print_verbose(args, "want %s (%s)", oid_to_hex(remote), ref->name); continue; } print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote), ref->name); } save_commit_buffer = old_save_commit_buffer; return retval; }