From 17cabd369b5cb96bee9577f49247ef95d07058a7 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:52 +0100 Subject: [PATCH 01/12] fetch-pack: move fsck options into function scope When fetching a packfile, we optionally verify received objects via the fsck subsystem. The options for those consistency checks are declared in global scope without a good reason, and they are never cleaned up. So in case the options are reused, they may accumulate more state over time. Furthermore, in subsequent changes we'll introduce a repository pointer into the structure. Obviously though, we don't have a repository available at static time, except for `the_repository`, which we don't want to use here. Refactor the code to move the options into the respective functions and properly manage their lifecycle. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- fetch-pack.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fetch-pack.c b/fetch-pack.c index 6ecd468ef7..ec5abb92b5 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -51,7 +51,6 @@ static int server_supports_filtering; static int advertise_sid; static struct shallow_lock shallow_lock; static const char *alternate_shallow_file; -static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; static struct strbuf fsck_msg_types = STRBUF_INIT; static struct string_list uri_protocols = STRING_LIST_INIT_DUP; @@ -1100,6 +1099,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, struct shallow_info *si, struct string_list *pack_lockfiles) { + struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; struct repository *r = the_repository; struct ref *ref = copy_ref_list(orig_ref); struct object_id oid; @@ -1235,6 +1235,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, die("fsck failed"); all_done: + fsck_options_clear(&fsck_options); if (negotiator) negotiator->release(negotiator); return ref; @@ -1654,6 +1655,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct string_list *pack_lockfiles) { struct repository *r = the_repository; + struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; @@ -1882,6 +1884,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, if (negotiator) negotiator->release(negotiator); + fsck_options_clear(&fsck_options); oidset_clear(&common); return ref; } From f22360902621e0807a1c0a77476e3e4d323c708d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:53 +0100 Subject: [PATCH 02/12] fsck: initialize fsck options via a function We initialize the `struct fsck_options` via a set of macros, often in global scope. In the next commit though we're about to introduce a new repository field to the options that must be initialized, and naturally we don't have a repo other than `the_repository` available in this scope. Refactor the code to instead intrdouce a new `fsck_options_init()` function that initializes the options for us and move initialization into function scope. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 10 ++++++--- builtin/index-pack.c | 4 +++- builtin/mktag.c | 3 ++- builtin/refs.c | 4 +++- builtin/unpack-objects.c | 4 +++- fetch-pack.c | 8 +++++-- fsck.c | 45 ++++++++++++++++++++++++++++++++++++++++ fsck.h | 38 +++++++++------------------------ object-file.c | 3 ++- 9 files changed, 81 insertions(+), 38 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 9bab32effe..59e3b0f7ac 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -42,8 +42,8 @@ static int check_full = 1; static int connectivity_only; static int check_strict; static int keep_cache_objects; -static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT; -static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT; +static struct fsck_options fsck_walk_options; +static struct fsck_options fsck_obj_options; static int errors_found; static int write_lost_and_found; static int verbose; @@ -224,7 +224,7 @@ static int mark_unreachable_referents(const struct object_id *oid, struct object_info *oi UNUSED, void *data UNUSED) { - struct fsck_options options = FSCK_OPTIONS_DEFAULT; + struct fsck_options options; struct object *obj = lookup_object(the_repository, oid); if (!obj || !(obj->flags & HAS_OBJ)) @@ -243,6 +243,7 @@ static int mark_unreachable_referents(const struct object_id *oid, object_as_type(obj, type, 0); } + fsck_options_init(&options, FSCK_OPTIONS_DEFAULT); options.walk = mark_used; fsck_walk(obj, NULL, &options); if (obj->type == OBJ_TREE) @@ -1004,7 +1005,10 @@ int cmd_fsck(int argc, argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0); + fsck_options_init(&fsck_walk_options, FSCK_OPTIONS_DEFAULT); fsck_walk_options.walk = mark_object; + + fsck_options_init(&fsck_obj_options, FSCK_OPTIONS_DEFAULT); fsck_obj_options.walk = mark_used; fsck_obj_options.error_func = fsck_objects_error_func; if (check_strict) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index d1e47279a8..c8d28bcf8e 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -136,7 +136,7 @@ static int nr_threads; static int from_stdin; static int strict; static int do_fsck_object; -static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; +static struct fsck_options fsck_options; static int verbose; static const char *progress_title; static int show_resolving_progress; @@ -1908,6 +1908,8 @@ int cmd_index_pack(int argc, show_usage_if_asked(argc, argv, index_pack_usage); disable_replace_refs(); + + fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); fsck_options.walk = mark_link; reset_pack_idx_option(&opts); diff --git a/builtin/mktag.c b/builtin/mktag.c index 7cf6e1230a..9f37f9dede 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -16,7 +16,7 @@ static char const * const builtin_mktag_usage[] = { }; static int option_strict = 1; -static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT; +static struct fsck_options fsck_options; static int mktag_fsck_error_func(struct fsck_options *o UNUSED, void *fsck_report UNUSED, @@ -94,6 +94,7 @@ int cmd_mktag(int argc, if (strbuf_read(&buf, 0, 0) < 0) die_errno(_("could not read from stdin")); + fsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT); fsck_options.error_func = mktag_fsck_error_func; fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY, FSCK_WARN); diff --git a/builtin/refs.c b/builtin/refs.c index 3064f888b2..1719ada549 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -80,7 +80,7 @@ out: static int cmd_refs_verify(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { - struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT; + struct fsck_options fsck_refs_options; struct worktree **worktrees; const char * const verify_usage[] = { REFS_VERIFY_USAGE, @@ -93,6 +93,8 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix, }; int ret = 0; + fsck_options_init(&fsck_refs_options, FSCK_OPTIONS_REFS); + argc = parse_options(argc, argv, prefix, options, verify_usage, 0); if (argc) usage(_("'git refs verify' takes no arguments")); diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 6fc64e9e4b..9e4bb9d25c 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -29,7 +29,7 @@ static unsigned int offset, len; static off_t consumed_bytes; static off_t max_input_size; static struct git_hash_ctx ctx; -static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT; +static struct fsck_options fsck_options; static struct progress *progress; /* @@ -627,6 +627,8 @@ int cmd_unpack_objects(int argc, show_usage_if_asked(argc, argv, unpack_usage); + fsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT); + for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; diff --git a/fetch-pack.c b/fetch-pack.c index ec5abb92b5..7339162368 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1099,7 +1099,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, struct shallow_info *si, struct string_list *pack_lockfiles) { - struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; + struct fsck_options fsck_options = { 0 }; struct repository *r = the_repository; struct ref *ref = copy_ref_list(orig_ref); struct object_id oid; @@ -1228,6 +1228,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, alternate_shallow_file = setup_temporary_shallow(si->shallow); } else alternate_shallow_file = NULL; + + fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought, &fsck_options.gitmodules_found)) die(_("git fetch-pack: fetch failed.")); @@ -1655,7 +1657,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct string_list *pack_lockfiles) { struct repository *r = the_repository; - struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES; + struct fsck_options fsck_options; struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; @@ -1673,6 +1675,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct strvec index_pack_args = STRVEC_INIT; const char *promisor_remote_config; + fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); + if (server_feature_v2("promisor-remote", &promisor_remote_config)) promisor_remote_reply(promisor_remote_config, NULL); diff --git a/fsck.c b/fsck.c index 0f02cf8f77..1ff8208502 100644 --- a/fsck.c +++ b/fsck.c @@ -1380,6 +1380,51 @@ bool fsck_has_queued_checks(struct fsck_options *options) !oidset_equal(&options->gitattributes_found, &options->gitattributes_done); } +void fsck_options_init(struct fsck_options *options, + enum fsck_options_type type) +{ + static const struct fsck_options defaults[] = { + [FSCK_OPTIONS_DEFAULT] = { + .skip_oids = OIDSET_INIT, + .gitmodules_found = OIDSET_INIT, + .gitmodules_done = OIDSET_INIT, + .gitattributes_found = OIDSET_INIT, + .gitattributes_done = OIDSET_INIT, + .error_func = fsck_objects_error_function + }, + [FSCK_OPTIONS_STRICT] = { + .strict = 1, + .gitmodules_found = OIDSET_INIT, + .gitmodules_done = OIDSET_INIT, + .gitattributes_found = OIDSET_INIT, + .gitattributes_done = OIDSET_INIT, + .error_func = fsck_objects_error_function, + }, + [FSCK_OPTIONS_MISSING_GITMODULES] = { + .strict = 1, + .gitmodules_found = OIDSET_INIT, + .gitmodules_done = OIDSET_INIT, + .gitattributes_found = OIDSET_INIT, + .gitattributes_done = OIDSET_INIT, + .error_func = fsck_objects_error_cb_print_missing_gitmodules, + }, + [FSCK_OPTIONS_REFS] = { + .error_func = fsck_refs_error_function, + }, + }; + + switch (type) { + case FSCK_OPTIONS_DEFAULT: + case FSCK_OPTIONS_STRICT: + case FSCK_OPTIONS_MISSING_GITMODULES: + case FSCK_OPTIONS_REFS: + memcpy(options, &defaults[type], sizeof(*options)); + break; + default: + BUG("unknown fsck options type %d", type); + } +} + void fsck_options_clear(struct fsck_options *options) { free(options->msg_type); diff --git a/fsck.h b/fsck.h index 65ecbb7fe1..9c973b53b2 100644 --- a/fsck.h +++ b/fsck.h @@ -180,34 +180,6 @@ struct fsck_options { kh_oid_map_t *object_names; }; -#define FSCK_OPTIONS_DEFAULT { \ - .skip_oids = OIDSET_INIT, \ - .gitmodules_found = OIDSET_INIT, \ - .gitmodules_done = OIDSET_INIT, \ - .gitattributes_found = OIDSET_INIT, \ - .gitattributes_done = OIDSET_INIT, \ - .error_func = fsck_objects_error_function \ -} -#define FSCK_OPTIONS_STRICT { \ - .strict = 1, \ - .gitmodules_found = OIDSET_INIT, \ - .gitmodules_done = OIDSET_INIT, \ - .gitattributes_found = OIDSET_INIT, \ - .gitattributes_done = OIDSET_INIT, \ - .error_func = fsck_objects_error_function, \ -} -#define FSCK_OPTIONS_MISSING_GITMODULES { \ - .strict = 1, \ - .gitmodules_found = OIDSET_INIT, \ - .gitmodules_done = OIDSET_INIT, \ - .gitattributes_found = OIDSET_INIT, \ - .gitattributes_done = OIDSET_INIT, \ - .error_func = fsck_objects_error_cb_print_missing_gitmodules, \ -} -#define FSCK_REFS_OPTIONS_DEFAULT { \ - .error_func = fsck_refs_error_function, \ -} - /* descend in all linked child objects * the return value is: * -1 error in processing the object @@ -255,6 +227,16 @@ int fsck_finish(struct fsck_options *options); */ bool fsck_has_queued_checks(struct fsck_options *options); +enum fsck_options_type { + FSCK_OPTIONS_DEFAULT, + FSCK_OPTIONS_STRICT, + FSCK_OPTIONS_MISSING_GITMODULES, + FSCK_OPTIONS_REFS, +}; + +void fsck_options_init(struct fsck_options *options, + enum fsck_options_type type); + /* * Clear the fsck_options struct, freeing any allocated memory. */ diff --git a/object-file.c b/object-file.c index c62e5496e0..186b2ff764 100644 --- a/object-file.c +++ b/object-file.c @@ -1279,8 +1279,9 @@ static int index_mem(struct index_state *istate, } } if (flags & INDEX_FORMAT_CHECK) { - struct fsck_options opts = FSCK_OPTIONS_DEFAULT; + struct fsck_options opts; + fsck_options_init(&opts, FSCK_OPTIONS_DEFAULT); opts.strict = 1; opts.error_func = hash_format_check_report; if (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts)) From 374985390871cb67c02b1608b693480e89567b9a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:54 +0100 Subject: [PATCH 03/12] fsck: store repository in fsck options The fsck subsystem relies on `the_repository` quite a bit. While we could of course explicitly pass a repository down the callchain, we already have a `struct fsck_options` that we pass to almost all functions. Extend the options to also store the repository to make it readily available. Suggested-by: Junio C Hamano Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 8 ++++---- builtin/index-pack.c | 2 +- builtin/mktag.c | 4 ++-- builtin/refs.c | 4 ++-- builtin/unpack-objects.c | 4 ++-- fetch-pack.c | 4 ++-- fsck.c | 3 +++ fsck.h | 4 ++++ object-file.c | 2 +- 9 files changed, 21 insertions(+), 14 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 59e3b0f7ac..990d836918 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -243,7 +243,7 @@ static int mark_unreachable_referents(const struct object_id *oid, object_as_type(obj, type, 0); } - fsck_options_init(&options, FSCK_OPTIONS_DEFAULT); + fsck_options_init(&options, the_repository, FSCK_OPTIONS_DEFAULT); options.walk = mark_used; fsck_walk(obj, NULL, &options); if (obj->type == OBJ_TREE) @@ -987,7 +987,7 @@ static struct option fsck_opts[] = { int cmd_fsck(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct odb_source *source; struct snapshot snap = { @@ -1005,10 +1005,10 @@ int cmd_fsck(int argc, argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0); - fsck_options_init(&fsck_walk_options, FSCK_OPTIONS_DEFAULT); + fsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT); fsck_walk_options.walk = mark_object; - fsck_options_init(&fsck_obj_options, FSCK_OPTIONS_DEFAULT); + fsck_options_init(&fsck_obj_options, repo, FSCK_OPTIONS_DEFAULT); fsck_obj_options.walk = mark_used; fsck_obj_options.error_func = fsck_objects_error_func; if (check_strict) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index c8d28bcf8e..e4129bd605 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1909,7 +1909,7 @@ int cmd_index_pack(int argc, disable_replace_refs(); - fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); + fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES); fsck_options.walk = mark_link; reset_pack_idx_option(&opts); diff --git a/builtin/mktag.c b/builtin/mktag.c index 9f37f9dede..f40264a878 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -75,7 +75,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type) int cmd_mktag(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { static struct option builtin_mktag_options[] = { OPT_BOOL(0, "strict", &option_strict, @@ -94,7 +94,7 @@ int cmd_mktag(int argc, if (strbuf_read(&buf, 0, 0) < 0) die_errno(_("could not read from stdin")); - fsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT); + fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT); fsck_options.error_func = mktag_fsck_error_func; fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY, FSCK_WARN); diff --git a/builtin/refs.c b/builtin/refs.c index 1719ada549..e3125bc61b 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -78,7 +78,7 @@ out: } static int cmd_refs_verify(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct fsck_options fsck_refs_options; struct worktree **worktrees; @@ -93,7 +93,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix, }; int ret = 0; - fsck_options_init(&fsck_refs_options, FSCK_OPTIONS_REFS); + fsck_options_init(&fsck_refs_options, repo, FSCK_OPTIONS_REFS); argc = parse_options(argc, argv, prefix, options, verify_usage, 0); if (argc) diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 9e4bb9d25c..d863912b24 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -613,7 +613,7 @@ static void unpack_all(void) int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED, - struct repository *repo UNUSED) + struct repository *repo) { int i; struct object_id oid; @@ -627,7 +627,7 @@ int cmd_unpack_objects(int argc, show_usage_if_asked(argc, argv, unpack_usage); - fsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT); + fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; diff --git a/fetch-pack.c b/fetch-pack.c index 7339162368..84a21c5107 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1229,7 +1229,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, } else alternate_shallow_file = NULL; - fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); + fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES); if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought, &fsck_options.gitmodules_found)) die(_("git fetch-pack: fetch failed.")); @@ -1675,7 +1675,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct strvec index_pack_args = STRVEC_INIT; const char *promisor_remote_config; - fsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES); + fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES); if (server_feature_v2("promisor-remote", &promisor_remote_config)) promisor_remote_reply(promisor_remote_config, NULL); diff --git a/fsck.c b/fsck.c index 1ff8208502..a05997703a 100644 --- a/fsck.c +++ b/fsck.c @@ -1381,6 +1381,7 @@ bool fsck_has_queued_checks(struct fsck_options *options) } void fsck_options_init(struct fsck_options *options, + struct repository *repo, enum fsck_options_type type) { static const struct fsck_options defaults[] = { @@ -1423,6 +1424,8 @@ void fsck_options_init(struct fsck_options *options, default: BUG("unknown fsck options type %d", type); } + + options->repo = repo; } void fsck_options_clear(struct fsck_options *options) diff --git a/fsck.h b/fsck.h index 9c973b53b2..e77935c8a9 100644 --- a/fsck.h +++ b/fsck.h @@ -166,7 +166,10 @@ struct fsck_ref_report { const char *path; }; +struct repository; + struct fsck_options { + struct repository *repo; fsck_walk_func walk; fsck_error error_func; unsigned strict; @@ -235,6 +238,7 @@ enum fsck_options_type { }; void fsck_options_init(struct fsck_options *options, + struct repository *repo, enum fsck_options_type type); /* diff --git a/object-file.c b/object-file.c index 186b2ff764..24ed5d5577 100644 --- a/object-file.c +++ b/object-file.c @@ -1281,7 +1281,7 @@ static int index_mem(struct index_state *istate, if (flags & INDEX_FORMAT_CHECK) { struct fsck_options opts; - fsck_options_init(&opts, FSCK_OPTIONS_DEFAULT); + fsck_options_init(&opts, the_repository, FSCK_OPTIONS_DEFAULT); opts.strict = 1; opts.error_func = hash_format_check_report; if (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts)) From fe5f16ecc39e2879e5b57925648984b78aaf6339 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:55 +0100 Subject: [PATCH 04/12] fsck: drop USE_THE_REPOSITORY Stop using `the_repository` in "fsck.c" in favor of the repository that we've already got available via `struct fsck_options`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- fsck.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/fsck.c b/fsck.c index a05997703a..b72200c352 100644 --- a/fsck.c +++ b/fsck.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "date.h" #include "dir.h" @@ -207,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values) if (equal == len) die("skiplist requires a path"); oidset_parse_file(&options->skip_oids, buf + equal + 1, - the_repository->hash_algo); + options->repo->hash_algo); buf += len + 1; continue; } @@ -360,7 +358,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op int res = 0; const char *name; - if (repo_parse_tree(the_repository, tree)) + if (repo_parse_tree(options->repo, tree)) return -1; name = fsck_get_object_name(options, &tree->object.oid); @@ -375,14 +373,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op continue; if (S_ISDIR(entry.mode)) { - obj = (struct object *)lookup_tree(the_repository, &entry.oid); + obj = (struct object *)lookup_tree(options->repo, &entry.oid); if (name && obj) fsck_put_object_name(options, &entry.oid, "%s%s/", name, entry.path); result = options->walk(obj, OBJ_TREE, data, options); } else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) { - obj = (struct object *)lookup_blob(the_repository, &entry.oid); + obj = (struct object *)lookup_blob(options->repo, &entry.oid); if (name && obj) fsck_put_object_name(options, &entry.oid, "%s%s", name, entry.path); @@ -409,7 +407,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio int result; const char *name; - if (repo_parse_commit(the_repository, commit)) + if (repo_parse_commit(options->repo, commit)) return -1; name = fsck_get_object_name(options, &commit->object.oid); @@ -417,7 +415,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio fsck_put_object_name(options, get_commit_tree_oid(commit), "%s:", name); - result = options->walk((struct object *) repo_get_commit_tree(the_repository, commit), + result = options->walk((struct object *) repo_get_commit_tree(options->repo, commit), OBJ_TREE, data, options); if (result < 0) return result; @@ -474,7 +472,7 @@ static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *optio { const char *name = fsck_get_object_name(options, &tag->object.oid); - if (parse_tag(the_repository, tag)) + if (parse_tag(options->repo, tag)) return -1; if (name) fsck_put_object_name(options, &tag->tagged->oid, "%s", name); @@ -487,7 +485,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options) return -1; if (obj->type == OBJ_NONE) - parse_object(the_repository, &obj->oid); + parse_object(options->repo, &obj->oid); switch (obj->type) { case OBJ_BLOB: @@ -970,14 +968,14 @@ static int fsck_commit(const struct object_id *oid, if (buffer >= buffer_end || !skip_prefix(buffer, "tree ", &buffer)) return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line"); - if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') { + if (parse_oid_hex_algop(buffer, &tree_oid, &p, options->repo->hash_algo) || *p != '\n') { err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1"); if (err) return err; } buffer = p + 1; while (buffer < buffer_end && skip_prefix(buffer, "parent ", &buffer)) { - if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') { + if (parse_oid_hex_algop(buffer, &parent_oid, &p, options->repo->hash_algo) || *p != '\n') { err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1"); if (err) return err; @@ -1044,7 +1042,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer, ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line"); goto done; } - if (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\n') { + if (parse_oid_hex_algop(buffer, tagged_oid, &p, options->repo->hash_algo) || *p != '\n') { ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1"); if (ret) goto done; @@ -1336,9 +1334,9 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done, if (oidset_contains(blobs_done, oid)) continue; - buf = odb_read_object(the_repository->objects, oid, &type, &size); + buf = odb_read_object(options->repo->objects, oid, &type, &size); if (!buf) { - if (is_promisor_object(the_repository, oid)) + if (is_promisor_object(options->repo, oid)) continue; ret |= report(options, oid, OBJ_BLOB, msg_missing, From da3ead3ee3a27df391932379b0b7283f2b17729f Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:56 +0100 Subject: [PATCH 05/12] builtin/fsck: fix trivial dependence on `the_repository` We have a bunch of sites in "builtin/fsck.c" that depend on `the_repository` even though we already have a repository available, or in cases where we can trivially make it available. Refactor such sites to use the context-provided repository instead. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 98 +++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 990d836918..59680e6daf 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -195,13 +195,13 @@ static int traverse_one_object(struct object *obj) return result; } -static int traverse_reachable(void) +static int traverse_reachable(struct repository *repo) { struct progress *progress = NULL; unsigned int nr = 0; int result = 0; if (show_progress) - progress = start_delayed_progress(the_repository, + progress = start_delayed_progress(repo, _("Checking connectivity"), 0); while (pending.nr) { result |= traverse_one_object(object_array_pop(&pending)); @@ -255,7 +255,7 @@ static int mark_unreachable_referents(const struct object_id *oid, /* * Check a single reachable object */ -static void check_reachable_object(struct object *obj) +static void check_reachable_object(struct repository *repo, struct object *obj) { /* * We obviously want the object to be parsed, @@ -263,9 +263,9 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!(obj->flags & HAS_OBJ)) { - if (is_promisor_object(the_repository, &obj->oid)) + if (is_promisor_object(repo, &obj->oid)) return; - if (has_object_pack(the_repository, &obj->oid)) + if (has_object_pack(repo, &obj->oid)) return; /* it is in pack - forget about it */ printf_ln(_("missing %s %s"), printable_type(&obj->oid, obj->type), @@ -278,7 +278,7 @@ static void check_reachable_object(struct object *obj) /* * Check a single unreachable object */ -static void check_unreachable_object(struct object *obj) +static void check_unreachable_object(struct repository *repo, struct object *obj) { /* * Missing unreachable object? Ignore it. It's not like @@ -318,19 +318,19 @@ static void check_unreachable_object(struct object *obj) printable_type(&obj->oid, obj->type), describe_object(&obj->oid)); if (write_lost_and_found) { - char *filename = repo_git_path(the_repository, "lost-found/%s/%s", + char *filename = repo_git_path(repo, "lost-found/%s/%s", obj->type == OBJ_COMMIT ? "commit" : "other", describe_object(&obj->oid)); FILE *f; - if (safe_create_leading_directories_const(the_repository, filename)) { + if (safe_create_leading_directories_const(repo, filename)) { error(_("could not create lost-found")); free(filename); return; } f = xfopen(filename, "w"); if (obj->type == OBJ_BLOB) { - if (odb_stream_blob_to_fd(the_repository->objects, fileno(f), + if (odb_stream_blob_to_fd(repo->objects, fileno(f), &obj->oid, NULL, 1)) die_errno(_("could not write '%s'"), filename); } else @@ -350,23 +350,23 @@ static void check_unreachable_object(struct object *obj) */ } -static void check_object(struct object *obj) +static void check_object(struct repository *repo, struct object *obj) { if (verbose) fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid)); if (obj->flags & REACHABLE) - check_reachable_object(obj); + check_reachable_object(repo, obj); else - check_unreachable_object(obj); + check_unreachable_object(repo, obj); } -static void check_connectivity(void) +static void check_connectivity(struct repository *repo) { int i, max; /* Traverse the pending reachable objects */ - traverse_reachable(); + traverse_reachable(repo); /* * With --connectivity-only, we won't have actually opened and marked @@ -384,20 +384,20 @@ static void check_connectivity(void) * and ignore any that weren't present in our earlier * traversal. */ - odb_for_each_object(the_repository->objects, NULL, + odb_for_each_object(repo->objects, NULL, mark_unreachable_referents, NULL, 0); } /* Look up all the requirements, warn about missing objects.. */ - max = get_max_object_index(the_repository); + max = get_max_object_index(repo); if (verbose) fprintf_ln(stderr, _("Checking connectivity (%d objects)"), max); for (i = 0; i < max; i++) { - struct object *obj = get_indexed_object(the_repository, i); + struct object *obj = get_indexed_object(repo, i); if (obj) - check_object(obj); + check_object(repo, obj); } } @@ -770,7 +770,7 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data) return 0; } -static void fsck_source(struct odb_source *source) +static void fsck_source(struct repository *repo, struct odb_source *source) { struct progress *progress = NULL; struct for_each_loose_cb cb_data = { @@ -781,7 +781,7 @@ static void fsck_source(struct odb_source *source) fprintf_ln(stderr, _("Checking object directory")); if (show_progress) - progress = start_progress(the_repository, + progress = start_progress(repo, _("Checking object directories"), 256); for_each_loose_file_in_source(source, fsck_loose, @@ -790,7 +790,7 @@ static void fsck_source(struct odb_source *source) stop_progress(&progress); } -static int fsck_cache_tree(struct cache_tree *it, const char *index_path) +static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const char *index_path) { int i; int err = 0; @@ -799,7 +799,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path) fprintf_ln(stderr, _("Checking cache tree of %s"), index_path); if (0 <= it->entry_count) { - struct object *obj = parse_object(the_repository, &it->oid); + struct object *obj = parse_object(repo, &it->oid); if (!obj) { error(_("%s: invalid sha1 pointer in cache-tree of %s"), oid_to_hex(&it->oid), index_path); @@ -813,7 +813,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path) err |= objerror(obj, _("non-tree in cache-tree")); } for (i = 0; i < it->subtree_nr; i++) - err |= fsck_cache_tree(it->down[i]->cache_tree, index_path); + err |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path); return err; } @@ -839,7 +839,7 @@ static int fsck_resolve_undo(struct index_state *istate, if (!ru->mode[i] || !S_ISREG(ru->mode[i])) continue; - obj = parse_object(the_repository, &ru->oid[i]); + obj = parse_object(istate->repo, &ru->oid[i]); if (!obj) { error(_("%s: invalid sha1 pointer in resolve-undo of %s"), oid_to_hex(&ru->oid[i]), @@ -871,7 +871,7 @@ static void fsck_index(struct index_state *istate, const char *index_path, mode = istate->cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; - blob = lookup_blob(the_repository, + blob = lookup_blob(istate->repo, &istate->cache[i]->oid); if (!blob) continue; @@ -884,7 +884,7 @@ static void fsck_index(struct index_state *istate, const char *index_path, mark_object_reachable(obj); } if (istate->cache_tree) - fsck_cache_tree(istate->cache_tree, index_path); + fsck_cache_tree(istate->repo, istate->cache_tree, index_path); fsck_resolve_undo(istate, index_path); } @@ -907,7 +907,7 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress) if (show_progress) { repo_for_each_pack(r, p) pack_count++; - progress = start_delayed_progress(the_repository, + progress = start_delayed_progress(r, "Verifying reverse pack-indexes", pack_count); pack_count = 0; } @@ -1027,11 +1027,11 @@ int cmd_fsck(int argc, if (name_objects) fsck_enable_object_names(&fsck_walk_options); - repo_config(the_repository, git_fsck_config, &fsck_obj_options); - prepare_repo_settings(the_repository); + repo_config(repo, git_fsck_config, &fsck_obj_options); + prepare_repo_settings(repo); if (check_references) - fsck_refs(the_repository); + fsck_refs(repo); /* * Take a snapshot of the refs before walking objects to avoid looking @@ -1042,15 +1042,15 @@ int cmd_fsck(int argc, snapshot_refs(&snap, argc, argv); /* Ensure we get a "fresh" view of the odb */ - odb_reprepare(the_repository->objects); + odb_reprepare(repo->objects); if (connectivity_only) { - odb_for_each_object(the_repository->objects, NULL, + odb_for_each_object(repo->objects, NULL, mark_object_for_connectivity, NULL, 0); } else { - odb_prepare_alternates(the_repository->objects); - for (source = the_repository->objects->sources; source; source = source->next) - fsck_source(source); + odb_prepare_alternates(repo->objects); + for (source = repo->objects->sources; source; source = source->next) + fsck_source(repo, source); if (check_full) { struct packed_git *p; @@ -1058,19 +1058,19 @@ int cmd_fsck(int argc, struct progress *progress = NULL; if (show_progress) { - repo_for_each_pack(the_repository, p) { + repo_for_each_pack(repo, p) { if (open_pack_index(p)) continue; total += p->num_objects; } - progress = start_progress(the_repository, + progress = start_progress(repo, _("Checking objects"), total); } - repo_for_each_pack(the_repository, p) { + repo_for_each_pack(repo, p) { /* verify gives error messages itself */ - if (verify_pack(the_repository, + if (verify_pack(repo, p, fsck_obj_buffer, progress, count)) errors_found |= ERROR_PACK; @@ -1104,7 +1104,7 @@ int cmd_fsck(int argc, for (p = worktrees; *p; p++) { struct worktree *wt = *p; struct index_state istate = - INDEX_STATE_INIT(the_repository); + INDEX_STATE_INIT(repo); char *path, *wt_gitdir; /* @@ -1125,17 +1125,17 @@ int cmd_fsck(int argc, free_worktrees(worktrees); } - errors_found |= check_pack_rev_indexes(the_repository, show_progress); - if (verify_bitmap_files(the_repository)) + errors_found |= check_pack_rev_indexes(repo, show_progress); + if (verify_bitmap_files(repo)) errors_found |= ERROR_BITMAP; - check_connectivity(); + check_connectivity(repo); - if (the_repository->settings.core_commit_graph) { + if (repo->settings.core_commit_graph) { struct child_process commit_graph_verify = CHILD_PROCESS_INIT; - odb_prepare_alternates(the_repository->objects); - for (source = the_repository->objects->sources; source; source = source->next) { + odb_prepare_alternates(repo->objects); + for (source = repo->objects->sources; source; source = source->next) { child_process_init(&commit_graph_verify); commit_graph_verify.git_cmd = 1; strvec_pushl(&commit_graph_verify.args, "commit-graph", @@ -1149,11 +1149,11 @@ int cmd_fsck(int argc, } } - if (the_repository->settings.core_multi_pack_index) { + if (repo->settings.core_multi_pack_index) { struct child_process midx_verify = CHILD_PROCESS_INIT; - odb_prepare_alternates(the_repository->objects); - for (source = the_repository->objects->sources; source; source = source->next) { + odb_prepare_alternates(repo->objects); + for (source = repo->objects->sources; source; source = source->next) { child_process_init(&midx_verify); midx_verify.git_cmd = 1; strvec_pushl(&midx_verify.args, "multi-pack-index", From 4c44db7dc55c1aac0d0414ed22c27ea965cc2c77 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:57 +0100 Subject: [PATCH 06/12] builtin/fsck: stop using `the_repository` when snapshotting refs We depedn on `the_repository` when snapshotting refs. Refactor this to use a context-provided repository instead that is injected via the `struct snapshot_ref_data`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 59680e6daf..edbff16add 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -533,14 +533,20 @@ struct snapshot { /* TODO: Consider also snapshotting the index of each worktree. */ }; +struct snapshot_ref_data { + struct repository *repo; + struct snapshot *snap; +}; + static int snapshot_ref(const struct reference *ref, void *cb_data) { - struct snapshot *snap = cb_data; + struct snapshot_ref_data *data = cb_data; + struct snapshot *snap = data->snap; struct object *obj; - obj = parse_object(the_repository, ref->oid); + obj = parse_object(data->repo, ref->oid); if (!obj) { - if (is_promisor_object(the_repository, ref->oid)) { + if (is_promisor_object(data->repo, ref->oid)) { /* * Increment default_refs anyway, because this is a * valid ref. @@ -581,11 +587,16 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED) return 0; } -static void snapshot_refs(struct snapshot *snap, int argc, const char **argv) +static void snapshot_refs(struct repository *repo, + struct snapshot *snap, int argc, const char **argv) { struct refs_for_each_ref_options opts = { .flags = REFS_FOR_EACH_INCLUDE_BROKEN, }; + struct snapshot_ref_data data = { + .repo = repo, + .snap = snap, + }; struct worktree **worktrees, **p; const char *head_points_at; struct object_id head_oid; @@ -593,13 +604,13 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv) for (int i = 0; i < argc; i++) { const char *arg = argv[i]; struct object_id oid; - if (!repo_get_oid(the_repository, arg, &oid)) { + if (!repo_get_oid(repo, arg, &oid)) { struct reference ref = { .name = arg, .oid = &oid, }; - snapshot_ref(&ref, snap); + snapshot_ref(&ref, &data); continue; } error(_("invalid parameter: expected sha1, got '%s'"), arg); @@ -611,8 +622,8 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv) return; } - refs_for_each_ref_ext(get_main_ref_store(the_repository), - snapshot_ref, snap, &opts); + refs_for_each_ref_ext(get_main_ref_store(repo), + snapshot_ref, &data, &opts); worktrees = get_worktrees(); for (p = worktrees; *p; p++) { @@ -621,7 +632,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv) strbuf_worktree_ref(wt, &refname, "HEAD"); - head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo), refname.buf, 0, &head_oid, NULL); if (head_points_at && !is_null_oid(&head_oid)) { @@ -630,7 +641,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv) .oid = &head_oid, }; - snapshot_ref(&ref, snap); + snapshot_ref(&ref, &data); } strbuf_release(&refname); @@ -1039,7 +1050,7 @@ int cmd_fsck(int argc, * objects. We can still walk over new objects that are added during the * execution of fsck but won't miss any objects that were reachable. */ - snapshot_refs(&snap, argc, argv); + snapshot_refs(repo, &snap, argc, argv); /* Ensure we get a "fresh" view of the odb */ odb_reprepare(repo->objects); From 3ea779432d28b0229ef2a64e6a73a9018ad4c940 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:58 +0100 Subject: [PATCH 07/12] builtin/fsck: stop using `the_repository` when checking refs We implicitly rely on `the_repository` when checking refs. Refactor this to instead inject the repository via the callback payload. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index edbff16add..efc60862ae 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -574,11 +574,12 @@ static int snapshot_ref(const struct reference *ref, void *cb_data) return 0; } -static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED) +static int fsck_handle_ref(const struct reference *ref, void *cb_data) { + struct repository *repo = cb_data; struct object *obj; - obj = parse_object(the_repository, ref->oid); + obj = parse_object(repo, ref->oid); obj->flags |= USED; fsck_put_object_name(&fsck_walk_options, ref->oid, "%s", ref->name); @@ -665,7 +666,7 @@ static void free_snapshot_refs(struct snapshot *snap) free(snap->ref); } -static void process_refs(struct snapshot *snap) +static void process_refs(struct repository *repo, struct snapshot *snap) { struct worktree **worktrees, **p; @@ -674,7 +675,7 @@ static void process_refs(struct snapshot *snap) .name = snap->ref[i].refname, .oid = &snap->ref[i].oid, }; - fsck_handle_ref(&ref, NULL); + fsck_handle_ref(&ref, repo); } if (include_reflogs) { @@ -1095,7 +1096,7 @@ int cmd_fsck(int argc, } /* Process the snapshotted refs and the reflogs. */ - process_refs(&snap); + process_refs(repo, &snap); /* If not given any explicit objects, process index files too. */ if (!argc) From 38e09ebfd444f04e7282e5a7109edb6800864d41 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:02:59 +0100 Subject: [PATCH 08/12] builtin/fsck: stop using `the_repository` when checking reflogs We implicitly rely on `the_repository` when checking reflogs. Refactor this to instead inject the repository via the callback payload. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index efc60862ae..be9dbba2da 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -468,13 +468,14 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, static int default_refs; -static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, - timestamp_t timestamp) +static void fsck_handle_reflog_oid(struct repository *repo, + const char *refname, struct object_id *oid, + timestamp_t timestamp) { struct object *obj; if (!is_null_oid(oid)) { - obj = lookup_object(the_repository, oid); + obj = lookup_object(repo, oid); if (obj && (obj->flags & HAS_OBJ)) { if (timestamp) fsck_put_object_name(&fsck_walk_options, oid, @@ -482,7 +483,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, refname, timestamp); obj->flags |= USED; mark_object_reachable(obj); - } else if (!is_promisor_object(the_repository, oid)) { + } else if (!is_promisor_object(repo, oid)) { error(_("%s: invalid reflog entry %s"), refname, oid_to_hex(oid)); errors_found |= ERROR_REACHABLE; @@ -494,8 +495,10 @@ static int fsck_handle_reflog_ent(const char *refname, struct object_id *ooid, struct object_id *noid, const char *email UNUSED, timestamp_t timestamp, int tz UNUSED, - const char *message UNUSED, void *cb_data UNUSED) + const char *message UNUSED, void *cb_data) { + struct repository *repo = cb_data; + if (now && timestamp > now) return 0; @@ -503,19 +506,20 @@ static int fsck_handle_reflog_ent(const char *refname, fprintf_ln(stderr, _("Checking reflog %s->%s"), oid_to_hex(ooid), oid_to_hex(noid)); - fsck_handle_reflog_oid(refname, ooid, 0); - fsck_handle_reflog_oid(refname, noid, timestamp); + fsck_handle_reflog_oid(repo, refname, ooid, 0); + fsck_handle_reflog_oid(repo, refname, noid, timestamp); return 0; } static int fsck_handle_reflog(const char *logname, void *cb_data) { struct strbuf refname = STRBUF_INIT; + struct worktree *wt = cb_data; - strbuf_worktree_ref(cb_data, &refname, logname); - refs_for_each_reflog_ent(get_main_ref_store(the_repository), + strbuf_worktree_ref(wt, &refname, logname); + refs_for_each_reflog_ent(get_main_ref_store(wt->repo), refname.buf, fsck_handle_reflog_ent, - NULL); + wt->repo); strbuf_release(&refname); return 0; } From 2b2287c479ced6f794a7c8d305c39eef4ee563f5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:03:00 +0100 Subject: [PATCH 09/12] builtin/fsck: stop using `the_repository` with loose objects We depend on `the_repository` when performing consistency checks for loose objects. Refactor this to use a context-provided repository instead that is injected via the `struct for_each_loose_cb`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index be9dbba2da..e8bdec7cd0 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -711,27 +711,28 @@ static void process_refs(struct repository *repo, struct snapshot *snap) } } -struct for_each_loose_cb -{ +struct for_each_loose_cb { + struct repository *repo; struct progress *progress; }; static int fsck_loose(const struct object_id *oid, const char *path, - void *data UNUSED) + void *cb_data) { + struct for_each_loose_cb *data = cb_data; struct object *obj; enum object_type type = OBJ_NONE; unsigned long size; void *contents = NULL; int eaten; struct object_info oi = OBJECT_INFO_INIT; - struct object_id real_oid = *null_oid(the_hash_algo); + struct object_id real_oid = *null_oid(data->repo->hash_algo); int err = 0; oi.sizep = &size; oi.typep = &type; - if (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) { + if (read_loose_object(data->repo, path, oid, &real_oid, &contents, &oi) < 0) { if (contents && !oideq(&real_oid, oid)) err = error(_("%s: hash-path mismatch, found at: %s"), oid_to_hex(&real_oid), path); @@ -748,7 +749,7 @@ static int fsck_loose(const struct object_id *oid, const char *path, if (!contents && type != OBJ_BLOB) BUG("read_loose_object streamed a non-blob"); - obj = parse_object_buffer(the_repository, oid, type, size, + obj = parse_object_buffer(data->repo, oid, type, size, contents, &eaten); if (!obj) { @@ -790,6 +791,7 @@ static void fsck_source(struct repository *repo, struct odb_source *source) { struct progress *progress = NULL; struct for_each_loose_cb cb_data = { + .repo = source->odb->repo, .progress = progress, }; From 1c5f77b6103adae5d45ae9ff24e9945b8f8b76c8 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:03:01 +0100 Subject: [PATCH 10/12] builtin/fsck: stop using `the_repository` when checking packed objects We implicitly rely on `the_repository` when checking objects part of a packfile. These objects are iterated over via `verify_pack()`, which is provided by the packfile subsystem, and a callback function is then invoked for each of the objects in that specific pack. Unfortunately, it is not possible to provide a payload to the callback function. Refactor `verify_pack()` to accept a payload that is passed through to the callback so that we can inject the repository and get rid of the use of `the_repository`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 11 ++++++----- pack-check.c | 7 ++++--- pack.h | 9 +++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index e8bdec7cd0..22ca1200a2 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -447,15 +447,16 @@ out: } static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, - unsigned long size, void *buffer, int *eaten) + unsigned long size, void *buffer, int *eaten, void *cb_data) { + struct repository *repo = cb_data; + struct object *obj; + /* * Note, buffer may be NULL if type is OBJ_BLOB. See * verify_packfile(), data_valid variable for details. */ - struct object *obj; - obj = parse_object_buffer(the_repository, oid, type, size, buffer, - eaten); + obj = parse_object_buffer(repo, oid, type, size, buffer, eaten); if (!obj) { errors_found |= ERROR_OBJECT; return error(_("%s: object corrupt or missing"), @@ -1089,7 +1090,7 @@ int cmd_fsck(int argc, repo_for_each_pack(repo, p) { /* verify gives error messages itself */ if (verify_pack(repo, - p, fsck_obj_buffer, + p, fsck_obj_buffer, repo, progress, count)) errors_found |= ERROR_PACK; count += p->num_objects; diff --git a/pack-check.c b/pack-check.c index 7378c80730..79992bb509 100644 --- a/pack-check.c +++ b/pack-check.c @@ -53,6 +53,7 @@ static int verify_packfile(struct repository *r, struct packed_git *p, struct pack_window **w_curs, verify_fn fn, + void *fn_data, struct progress *progress, uint32_t base_count) { @@ -161,7 +162,7 @@ static int verify_packfile(struct repository *r, oid_to_hex(&oid), p->pack_name); else if (fn) { int eaten = 0; - err |= fn(&oid, type, size, data, &eaten); + err |= fn(&oid, type, size, data, &eaten, fn_data); if (eaten) data = NULL; } @@ -192,7 +193,7 @@ int verify_pack_index(struct packed_git *p) return err; } -int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, +int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, void *fn_data, struct progress *progress, uint32_t base_count) { int err = 0; @@ -202,7 +203,7 @@ int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, if (!p->index_data) return -1; - err |= verify_packfile(r, p, &w_curs, fn, progress, base_count); + err |= verify_packfile(r, p, &w_curs, fn, fn_data, progress, base_count); unuse_pack(&w_curs); return err; diff --git a/pack.h b/pack.h index ec76472e49..1cde92082b 100644 --- a/pack.h +++ b/pack.h @@ -85,7 +85,11 @@ struct pack_idx_entry { struct progress; /* Note, the data argument could be NULL if object type is blob */ -typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*); +typedef int (*verify_fn)(const struct object_id *oid, + enum object_type type, + unsigned long size, + void *buffer, int *eaten, + void *fn_data); const char *write_idx_file(struct repository *repo, const char *index_name, @@ -95,7 +99,8 @@ const char *write_idx_file(struct repository *repo, const unsigned char *sha1); int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr); int verify_pack_index(struct packed_git *); -int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t); +int verify_pack(struct repository *, struct packed_git *, verify_fn fn, void *fn_data, + struct progress *, uint32_t); off_t write_pack_header(struct hashfile *f, uint32_t); void fixup_pack_header_footer(const struct git_hash_algo *, int, unsigned char *, const char *, uint32_t, From cc050f00cd969a72fcdad34e2308c7b19c1e68e6 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:03:02 +0100 Subject: [PATCH 11/12] builtin/fsck: stop using `the_repository` when marking objects We implicitly rely on `the_repository` when marking objects for connectivity. Refactor this to instead inject the repository via the callback payload. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index 22ca1200a2..e37f708480 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -124,7 +124,7 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED, static struct object_array pending; static int mark_object(struct object *obj, enum object_type type, - void *data, struct fsck_options *options UNUSED) + void *data, struct fsck_options *options) { struct object *parent = data; @@ -153,7 +153,7 @@ static int mark_object(struct object *obj, enum object_type type, return 0; obj->flags |= REACHABLE; - if (is_promisor_object(the_repository, &obj->oid)) + if (is_promisor_object(options->repo, &obj->oid)) /* * Further recursion does not need to be performed on this * object since it is a promisor object (so it does not need to @@ -162,7 +162,7 @@ static int mark_object(struct object *obj, enum object_type type, return 0; if (!(obj->flags & HAS_OBJ)) { - if (parent && !odb_has_object(the_repository->objects, &obj->oid, + if (parent && !odb_has_object(options->repo->objects, &obj->oid, HAS_OBJECT_RECHECK_PACKED)) { printf_ln(_("broken link from %7s %s\n" " to %7s %s"), @@ -181,7 +181,7 @@ static int mark_object(struct object *obj, enum object_type type, static void mark_object_reachable(struct object *obj) { - mark_object(obj, OBJ_ANY, NULL, NULL); + mark_object(obj, OBJ_ANY, NULL, &fsck_walk_options); } static int traverse_one_object(struct object *obj) @@ -222,10 +222,11 @@ static int mark_used(struct object *obj, enum object_type type UNUSED, static int mark_unreachable_referents(const struct object_id *oid, struct object_info *oi UNUSED, - void *data UNUSED) + void *data) { + struct repository *repo = data; struct fsck_options options; - struct object *obj = lookup_object(the_repository, oid); + struct object *obj = lookup_object(data, oid); if (!obj || !(obj->flags & HAS_OBJ)) return 0; /* not part of our original set */ @@ -237,13 +238,13 @@ static int mark_unreachable_referents(const struct object_id *oid, * (and we want to avoid parsing blobs). */ if (obj->type == OBJ_NONE) { - enum object_type type = odb_read_object_info(the_repository->objects, + enum object_type type = odb_read_object_info(repo->objects, &obj->oid, NULL); if (type > 0) object_as_type(obj, type, 0); } - fsck_options_init(&options, the_repository, FSCK_OPTIONS_DEFAULT); + fsck_options_init(&options, repo, FSCK_OPTIONS_DEFAULT); options.walk = mark_used; fsck_walk(obj, NULL, &options); if (obj->type == OBJ_TREE) @@ -385,7 +386,7 @@ static void check_connectivity(struct repository *repo) * traversal. */ odb_for_each_object(repo->objects, NULL, - mark_unreachable_referents, NULL, 0); + mark_unreachable_referents, repo, 0); } /* Look up all the requirements, warn about missing objects.. */ @@ -909,9 +910,10 @@ static void fsck_index(struct index_state *istate, const char *index_path, static int mark_object_for_connectivity(const struct object_id *oid, struct object_info *oi UNUSED, - void *cb_data UNUSED) + void *cb_data) { - struct object *obj = lookup_unknown_object(the_repository, oid); + struct repository *repo = cb_data; + struct object *obj = lookup_unknown_object(repo, oid); obj->flags |= HAS_OBJ; return 0; } @@ -1065,7 +1067,7 @@ int cmd_fsck(int argc, if (connectivity_only) { odb_for_each_object(repo->objects, NULL, - mark_object_for_connectivity, NULL, 0); + mark_object_for_connectivity, repo, 0); } else { odb_prepare_alternates(repo->objects); for (source = repo->objects->sources; source; source = source->next) From 6fea405bb92100a229c0ee83c98e062e271577cd Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 23 Mar 2026 16:03:03 +0100 Subject: [PATCH 12/12] builtin/fsck: stop using `the_repository` in error reporting In the preceding commit we have introduced the repository into `struct fsck_object_report`. This allows us to drop remaining uses of the global `the_repository` variable. Drop them and remove `USE_THE_REPOSITORY_VARIABLE`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fsck.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/builtin/fsck.c b/builtin/fsck.c index e37f708480..99696604b8 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "gettext.h" #include "hex.h" @@ -66,14 +65,14 @@ static const char *describe_object(const struct object_id *oid) return fsck_describe_object(&fsck_walk_options, oid); } -static const char *printable_type(const struct object_id *oid, +static const char *printable_type(struct repository *repo, + const struct object_id *oid, enum object_type type) { const char *ret; if (type == OBJ_NONE) - type = odb_read_object_info(the_repository->objects, - oid, NULL); + type = odb_read_object_info(repo->objects, oid, NULL); ret = type_name(type); if (!ret) @@ -82,17 +81,17 @@ static const char *printable_type(const struct object_id *oid, return ret; } -static int objerror(struct object *obj, const char *err) +static int objerror(struct repository *repo, struct object *obj, const char *err) { errors_found |= ERROR_OBJECT; /* TRANSLATORS: e.g. error in tree 01bfda: */ fprintf_ln(stderr, _("error in %s %s: %s"), - printable_type(&obj->oid, obj->type), + printable_type(repo, &obj->oid, obj->type), describe_object(&obj->oid), err); return -1; } -static int fsck_objects_error_func(struct fsck_options *o UNUSED, +static int fsck_objects_error_func(struct fsck_options *o, void *fsck_report, enum fsck_msg_type msg_type, enum fsck_msg_id msg_id UNUSED, @@ -106,13 +105,13 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED, case FSCK_WARN: /* TRANSLATORS: e.g. warning in tree 01bfda: */ fprintf_ln(stderr, _("warning in %s %s: %s"), - printable_type(oid, object_type), + printable_type(o->repo, oid, object_type), describe_object(oid), message); return 0; case FSCK_ERROR: /* TRANSLATORS: e.g. error in tree 01bfda: */ fprintf_ln(stderr, _("error in %s %s: %s"), - printable_type(oid, object_type), + printable_type(o->repo, oid, object_type), describe_object(oid), message); return 1; default: @@ -136,7 +135,7 @@ static int mark_object(struct object *obj, enum object_type type, if (!obj) { /* ... these references to parent->fld are safe here */ printf_ln(_("broken link from %7s %s"), - printable_type(&parent->oid, parent->type), + printable_type(options->repo, &parent->oid, parent->type), describe_object(&parent->oid)); printf_ln(_("broken link from %7s %s"), (type == OBJ_ANY ? _("unknown") : type_name(type)), @@ -147,7 +146,7 @@ static int mark_object(struct object *obj, enum object_type type, if (type != OBJ_ANY && obj->type != type) /* ... and the reference to parent is safe here */ - objerror(parent, _("wrong object type in link")); + objerror(options->repo, parent, _("wrong object type in link")); if (obj->flags & REACHABLE) return 0; @@ -166,9 +165,9 @@ static int mark_object(struct object *obj, enum object_type type, HAS_OBJECT_RECHECK_PACKED)) { printf_ln(_("broken link from %7s %s\n" " to %7s %s"), - printable_type(&parent->oid, parent->type), + printable_type(options->repo, &parent->oid, parent->type), describe_object(&parent->oid), - printable_type(&obj->oid, obj->type), + printable_type(options->repo, &obj->oid, obj->type), describe_object(&obj->oid)); errors_found |= ERROR_REACHABLE; } @@ -269,7 +268,7 @@ static void check_reachable_object(struct repository *repo, struct object *obj) if (has_object_pack(repo, &obj->oid)) return; /* it is in pack - forget about it */ printf_ln(_("missing %s %s"), - printable_type(&obj->oid, obj->type), + printable_type(repo, &obj->oid, obj->type), describe_object(&obj->oid)); errors_found |= ERROR_REACHABLE; return; @@ -296,7 +295,7 @@ static void check_unreachable_object(struct repository *repo, struct object *obj */ if (show_unreachable) { printf_ln(_("unreachable %s %s"), - printable_type(&obj->oid, obj->type), + printable_type(repo, &obj->oid, obj->type), describe_object(&obj->oid)); return; } @@ -316,7 +315,7 @@ static void check_unreachable_object(struct repository *repo, struct object *obj if (!(obj->flags & USED)) { if (show_dangling) printf_ln(_("dangling %s %s"), - printable_type(&obj->oid, obj->type), + printable_type(repo, &obj->oid, obj->type), describe_object(&obj->oid)); if (write_lost_and_found) { char *filename = repo_git_path(repo, "lost-found/%s/%s", @@ -402,7 +401,8 @@ static void check_connectivity(struct repository *repo) } } -static int fsck_obj(struct object *obj, void *buffer, unsigned long size) +static int fsck_obj(struct repository *repo, + struct object *obj, void *buffer, unsigned long size) { int err; @@ -412,11 +412,11 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size) if (verbose) fprintf_ln(stderr, _("Checking %s %s"), - printable_type(&obj->oid, obj->type), + printable_type(repo, &obj->oid, obj->type), describe_object(&obj->oid)); if (fsck_walk(obj, NULL, &fsck_obj_options)) - objerror(obj, _("broken links")); + objerror(repo, obj, _("broken links")); err = fsck_object(obj, buffer, size, &fsck_obj_options); if (err) goto out; @@ -434,7 +434,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size) if (show_tags && tag->tagged) { printf_ln(_("tagged %s %s (%s) in %s"), - printable_type(&tag->tagged->oid, tag->tagged->type), + printable_type(repo, &tag->tagged->oid, tag->tagged->type), describe_object(&tag->tagged->oid), tag->tag, describe_object(&tag->object.oid)); @@ -465,7 +465,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, } obj->flags &= ~(REACHABLE | SEEN); obj->flags |= HAS_OBJ; - return fsck_obj(obj, buffer, size); + return fsck_obj(repo, obj, buffer, size); } static int default_refs; @@ -765,7 +765,7 @@ static int fsck_loose(const struct object_id *oid, const char *path, obj->flags &= ~(REACHABLE | SEEN); obj->flags |= HAS_OBJ; - if (fsck_obj(obj, contents, size)) + if (fsck_obj(data->repo, obj, contents, size)) errors_found |= ERROR_OBJECT; if (!eaten) @@ -830,7 +830,7 @@ static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const fsck_put_object_name(&fsck_walk_options, &it->oid, ":"); mark_object_reachable(obj); if (obj->type != OBJ_TREE) - err |= objerror(obj, _("non-tree in cache-tree")); + err |= objerror(repo, obj, _("non-tree in cache-tree")); } for (i = 0; i < it->subtree_nr; i++) err |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path);