{"thread":{"id":"65337","subject":"[PATCH v2 01/12] fetch-pack: move fsck options into function scope","startedAt":"2026-03-23T15:03:12Z","lastAt":"2026-03-31T22:50:43Z","messageCount":17,"participants":["Patrick Steinhardt","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":12},"messages":[{"id":"539735","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260320-b4-pks-fsck-without-the-repository-v1-0-6594f997926b@pks.im","subject":"[PATCH v2 00/12] fsck: drop use of `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:51Z","receivedAt":"2026-03-23T15:03:11Z","isPatch":true,"body":"Hi,\n\nthis patch series refactors \"{builtin/,}fsck.c\" to not depend on\n`the_repository` anymore. These refactorings are mostly done to prepare\nfor upcoming changes where we'll make backend-specific fsck checks\npluggable.\n\nChanges in v2:\n  - Propagate the repository via `struct fsck_options`.\n  - Link to v1: https://lore.kernel.org/r/20260320-b4-pks-fsck-without-the-repository-v1-0-6594f997926b@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (12):\n      fetch-pack: move fsck options into function scope\n      fsck: initialize fsck options via a function\n      fsck: store repository in fsck options\n      fsck: drop USE_THE_REPOSITORY\n      builtin/fsck: fix trivial dependence on `the_repository`\n      builtin/fsck: stop using `the_repository` when snapshotting refs\n      builtin/fsck: stop using `the_repository` when checking refs\n      builtin/fsck: stop using `the_repository` when checking reflogs\n      builtin/fsck: stop using `the_repository` with loose objects\n      builtin/fsck: stop using `the_repository` when checking packed objects\n      builtin/fsck: stop using `the_repository` when marking objects\n      builtin/fsck: stop using `the_repository` in error reporting\n\n builtin/fsck.c           | 273 ++++++++++++++++++++++++++---------------------\n builtin/index-pack.c     |   4 +-\n builtin/mktag.c          |   5 +-\n builtin/refs.c           |   6 +-\n builtin/unpack-objects.c |   6 +-\n fetch-pack.c             |   9 +-\n fsck.c                   |  76 ++++++++++---\n fsck.h                   |  42 +++-----\n object-file.c            |   3 +-\n pack-check.c             |   7 +-\n pack.h                   |   9 +-\n 11 files changed, 259 insertions(+), 181 deletions(-)\n\nRange-diff versus v1:\n\n 1:  fd589e1813 <  -:  ---------- fsck: drop `the_repository` in `fsck_walk()`\n 2:  6d0d46b70d <  -:  ---------- fsck: drop `the_repository` in `fsck_finish()`\n 3:  79c3cd644b <  -:  ---------- fsck: refactor interface to parse fsck options\n 4:  f5fd9d1489 <  -:  ---------- fsck: drop `the_repository` in `fsck_set_msg_types()`\n 5:  58c145905e <  -:  ---------- fsck: stop relying on global state via `parse_oid_hex()`\n -:  ---------- >  1:  1b5958d8db fetch-pack: move fsck options into function scope\n -:  ---------- >  2:  19b502cd82 fsck: initialize fsck options via a function\n -:  ---------- >  3:  34b921be8b fsck: store repository in fsck options\n -:  ---------- >  4:  f8a74307d8 fsck: drop USE_THE_REPOSITORY\n 6:  4d255cd44d !  5:  6e3f51757f builtin/fsck: fix trivial dependence on `the_repository`\n    @@ Commit message\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## builtin/fsck.c ##\n    -@@ builtin/fsck.c: static void mark_object_reachable(struct object *obj)\n    - \tmark_object(obj, OBJ_ANY, NULL, NULL);\n    - }\n    - \n    --static int traverse_one_object(struct object *obj)\n    -+static int traverse_one_object(struct repository *repo, struct object *obj)\n    - {\n    --\tint result = fsck_walk(the_repository, obj, obj, &fsck_walk_options);\n    -+\tint result = fsck_walk(repo, obj, obj, &fsck_walk_options);\n    - \n    - \tif (obj->type == OBJ_TREE) {\n    - \t\tstruct tree *tree = (struct tree *)obj;\n     @@ builtin/fsck.c: static int traverse_one_object(struct object *obj)\n      \treturn result;\n      }\n    @@ builtin/fsck.c: static int traverse_one_object(struct object *obj)\n     +\t\tprogress = start_delayed_progress(repo,\n      \t\t\t\t\t\t  _(\"Checking connectivity\"), 0);\n      \twhile (pending.nr) {\n    --\t\tresult |= traverse_one_object(object_array_pop(&pending));\n    -+\t\tresult |= traverse_one_object(repo, object_array_pop(&pending));\n    - \t\tdisplay_progress(progress, ++nr);\n    - \t}\n    - \tstop_progress(&progress);\n    + \t\tresult |= traverse_one_object(object_array_pop(&pending));\n     @@ builtin/fsck.c: static int mark_unreachable_referents(const struct object_id *oid,\n      /*\n       * Check a single reachable object\n    @@ builtin/fsck.c: static void check_connectivity(void)\n      \t}\n      }\n      \n    -@@ builtin/fsck.c: static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)\n    +@@ builtin/fsck.c: static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)\n      \treturn 0;\n      }\n      \n    --static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    -+static void snapshot_refs(struct repository *repo, struct snapshot *snap,\n    -+\t\t\t  int argc, const char **argv)\n    +-static void fsck_source(struct odb_source *source)\n    ++static void fsck_source(struct repository *repo, struct odb_source *source)\n      {\n    - \tstruct refs_for_each_ref_options opts = {\n    - \t\t.flags = REFS_FOR_EACH_INCLUDE_BROKEN,\n    -@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    - \tfor (int i = 0; i < argc; i++) {\n    - \t\tconst char *arg = argv[i];\n    - \t\tstruct object_id oid;\n    --\t\tif (!repo_get_oid(the_repository, arg, &oid)) {\n    -+\t\tif (!repo_get_oid(repo, arg, &oid)) {\n    - \t\t\tstruct reference ref = {\n    - \t\t\t\t.name = arg,\n    - \t\t\t\t.oid = &oid,\n    -@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    - \t\treturn;\n    - \t}\n    - \n    --\trefs_for_each_ref_ext(get_main_ref_store(the_repository),\n    -+\trefs_for_each_ref_ext(get_main_ref_store(repo),\n    - \t\t\t      snapshot_ref, snap, &opts);\n    - \n    - \tworktrees = get_worktrees();\n    -@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    - \n    - \t\tstrbuf_worktree_ref(wt, &refname, \"HEAD\");\n    - \n    --\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),\n    -+\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo),\n    - \t\t\t\t\t\t\t refname.buf, 0, &head_oid, NULL);\n    - \n    - \t\tif (head_points_at && !is_null_oid(&head_oid)) {\n    + \tstruct progress *progress = NULL;\n    + \tstruct for_each_loose_cb cb_data = {\n     @@ builtin/fsck.c: static void fsck_source(struct odb_source *source)\n      \t\tfprintf_ln(stderr, _(\"Checking object directory\"));\n      \n      \tif (show_progress)\n     -\t\tprogress = start_progress(the_repository,\n    -+\t\tprogress = start_progress(source->odb->repo,\n    ++\t\tprogress = start_progress(repo,\n      \t\t\t\t\t  _(\"Checking object directories\"), 256);\n      \n      \tfor_each_loose_file_in_source(source, fsck_loose,\n    @@ builtin/fsck.c: static void fsck_source(struct odb_source *source)\n      }\n      \n     -static int fsck_cache_tree(struct cache_tree *it, const char *index_path)\n    -+static int fsck_cache_tree(struct repository *repo, struct cache_tree *it,\n    -+\t\t\t   const char *index_path)\n    ++static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const char *index_path)\n      {\n      \tint i;\n      \tint err = 0;\n    @@ builtin/fsck.c: static int check_pack_rev_indexes(struct repository *r, int show\n      \t\t\t\t\t\t  \"Verifying reverse pack-indexes\", pack_count);\n      \t\tpack_count = 0;\n      \t}\n    -@@ builtin/fsck.c: static struct option fsck_opts[] = {\n    - int cmd_fsck(int argc,\n    - \t     const char **argv,\n    - \t     const char *prefix,\n    --\t     struct repository *repo UNUSED)\n    -+\t     struct repository *repo)\n    - {\n    - \tstruct odb_source *source;\n    - \tstruct snapshot snap = {\n     @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \tif (name_objects)\n      \t\tfsck_enable_object_names(&fsck_walk_options);\n      \n    --\tfsck_options_parse_config(&fsck_obj_options, the_repository);\n    +-\trepo_config(the_repository, git_fsck_config, &fsck_obj_options);\n     -\tprepare_repo_settings(the_repository);\n    -+\tfsck_options_parse_config(&fsck_obj_options, repo);\n    ++\trepo_config(repo, git_fsck_config, &fsck_obj_options);\n     +\tprepare_repo_settings(repo);\n      \n      \tif (check_references)\n    @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t/*\n      \t * Take a snapshot of the refs before walking objects to avoid looking\n     @@ builtin/fsck.c: int cmd_fsck(int argc,\n    - \t * objects. We can still walk over new objects that are added during the\n    - \t * execution of fsck but won't miss any objects that were reachable.\n    - \t */\n    --\tsnapshot_refs(&snap, argc, argv);\n    -+\tsnapshot_refs(repo, &snap, argc, argv);\n    + \tsnapshot_refs(&snap, argc, argv);\n      \n      \t/* Ensure we get a \"fresh\" view of the odb */\n     -\todb_reprepare(the_repository->objects);\n    @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t} else {\n     -\t\todb_prepare_alternates(the_repository->objects);\n     -\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n    +-\t\t\tfsck_source(source);\n     +\t\todb_prepare_alternates(repo->objects);\n     +\t\tfor (source = repo->objects->sources; source; source = source->next)\n    - \t\t\tfsck_source(source);\n    ++\t\t\tfsck_source(repo, source);\n      \n      \t\tif (check_full) {\n    + \t\t\tstruct packed_git *p;\n     @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t\t\tstruct progress *progress = NULL;\n      \n    @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t\t\t\t\t\tp, fsck_obj_buffer,\n      \t\t\t\t\t\tprogress, count))\n      \t\t\t\t\terrors_found |= ERROR_PACK;\n    -@@ builtin/fsck.c: int cmd_fsck(int argc,\n    - \t\t\tstop_progress(&progress);\n    - \t\t}\n    - \n    --\t\tif (fsck_finish(the_repository, &fsck_obj_options))\n    -+\t\tif (fsck_finish(repo, &fsck_obj_options))\n    - \t\t\terrors_found |= ERROR_OBJECT;\n    - \t}\n    - \n     @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t\tfor (p = worktrees; *p; p++) {\n      \t\t\tstruct worktree *wt = *p;\n 7:  65f1c0078b !  6:  6c0507a4c8 builtin/fsck: stop using `the_repository` when snapshotting refs\n    @@ builtin/fsck.c: struct snapshot {\n      \t\t\t/*\n      \t\t\t * Increment default_refs anyway, because this is a\n      \t\t\t * valid ref.\n    -@@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapshot *snap,\n    +@@ builtin/fsck.c: static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)\n    + \treturn 0;\n    + }\n    + \n    +-static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    ++static void snapshot_refs(struct repository *repo,\n    ++\t\t\t  struct snapshot *snap, int argc, const char **argv)\n    + {\n      \tstruct refs_for_each_ref_options opts = {\n      \t\t.flags = REFS_FOR_EACH_INCLUDE_BROKEN,\n      \t};\n    @@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapsh\n      \tstruct worktree **worktrees, **p;\n      \tconst char *head_points_at;\n      \tstruct object_id head_oid;\n    -@@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapshot *snap,\n    +@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    + \tfor (int i = 0; i < argc; i++) {\n    + \t\tconst char *arg = argv[i];\n    + \t\tstruct object_id oid;\n    +-\t\tif (!repo_get_oid(the_repository, arg, &oid)) {\n    ++\t\tif (!repo_get_oid(repo, arg, &oid)) {\n    + \t\t\tstruct reference ref = {\n    + \t\t\t\t.name = arg,\n      \t\t\t\t.oid = &oid,\n      \t\t\t};\n      \n    @@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapsh\n      \t\t\tcontinue;\n      \t\t}\n      \t\terror(_(\"invalid parameter: expected sha1, got '%s'\"), arg);\n    -@@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapshot *snap,\n    +@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    + \t\treturn;\n      \t}\n      \n    - \trefs_for_each_ref_ext(get_main_ref_store(repo),\n    +-\trefs_for_each_ref_ext(get_main_ref_store(the_repository),\n     -\t\t\t      snapshot_ref, snap, &opts);\n    ++\trefs_for_each_ref_ext(get_main_ref_store(repo),\n     +\t\t\t      snapshot_ref, &data, &opts);\n      \n      \tworktrees = get_worktrees();\n      \tfor (p = worktrees; *p; p++) {\n    -@@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapshot *snap,\n    +@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n    + \n    + \t\tstrbuf_worktree_ref(wt, &refname, \"HEAD\");\n    + \n    +-\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),\n    ++\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo),\n    + \t\t\t\t\t\t\t refname.buf, 0, &head_oid, NULL);\n    + \n    + \t\tif (head_points_at && !is_null_oid(&head_oid)) {\n    +@@ builtin/fsck.c: static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n      \t\t\t\t.oid = &head_oid,\n      \t\t\t};\n      \n    @@ builtin/fsck.c: static void snapshot_refs(struct repository *repo, struct snapsh\n      \t\t}\n      \t\tstrbuf_release(&refname);\n      \n    +@@ builtin/fsck.c: int cmd_fsck(int argc,\n    + \t * objects. We can still walk over new objects that are added during the\n    + \t * execution of fsck but won't miss any objects that were reachable.\n    + \t */\n    +-\tsnapshot_refs(&snap, argc, argv);\n    ++\tsnapshot_refs(repo, &snap, argc, argv);\n    + \n    + \t/* Ensure we get a \"fresh\" view of the odb */\n    + \todb_reprepare(repo->objects);\n 8:  42b9d4ad29 =  7:  844a192db2 builtin/fsck: stop using `the_repository` when checking refs\n 9:  3c3af4cbcd =  8:  6557fc60ee builtin/fsck: stop using `the_repository` when checking reflogs\n10:  387ba6f851 !  9:  31709b33c8 builtin/fsck: stop using `the_repository` with loose objects\n    @@ Commit message\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## builtin/fsck.c ##\n    -@@ builtin/fsck.c: static void check_connectivity(struct repository *repo)\n    - \t}\n    - }\n    - \n    --static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n    -+static int fsck_obj(struct repository *repo,\n    -+\t\t    struct object *obj,\n    -+\t\t    void *buffer, unsigned long size)\n    - {\n    - \tint err;\n    - \n    -@@ builtin/fsck.c: static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n    - \t\t\t   printable_type(&obj->oid, obj->type),\n    - \t\t\t   describe_object(&obj->oid));\n    - \n    --\tif (fsck_walk(the_repository, obj, NULL, &fsck_obj_options))\n    -+\tif (fsck_walk(repo, obj, NULL, &fsck_obj_options))\n    - \t\tobjerror(obj, _(\"broken links\"));\n    --\terr = fsck_object(the_repository, obj, buffer, size, &fsck_obj_options);\n    -+\terr = fsck_object(repo, obj, buffer, size, &fsck_obj_options);\n    - \tif (err)\n    - \t\tgoto out;\n    - \n    -@@ builtin/fsck.c: static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n    - \t}\n    - \tobj->flags &= ~(REACHABLE | SEEN);\n    - \tobj->flags |= HAS_OBJ;\n    --\treturn fsck_obj(obj, buffer, size);\n    -+\treturn fsck_obj(the_repository, obj, buffer, size);\n    - }\n    - \n    - static int default_refs;\n     @@ builtin/fsck.c: static void process_refs(struct repository *repo, struct snapshot *snap)\n      \t}\n      }\n    @@ builtin/fsck.c: static int fsck_loose(const struct object_id *oid, const char *p\n      \t\t\t\t  contents, &eaten);\n      \n      \tif (!obj) {\n    -@@ builtin/fsck.c: static int fsck_loose(const struct object_id *oid, const char *path,\n    - \n    - \tobj->flags &= ~(REACHABLE | SEEN);\n    - \tobj->flags |= HAS_OBJ;\n    --\tif (fsck_obj(obj, contents, size))\n    -+\tif (fsck_obj(data->repo, obj, contents, size))\n    - \t\terrors_found |= ERROR_OBJECT;\n    - \n    - \tif (!eaten)\n    -@@ builtin/fsck.c: static void fsck_source(struct odb_source *source)\n    +@@ builtin/fsck.c: static void fsck_source(struct repository *repo, struct odb_source *source)\n      {\n      \tstruct progress *progress = NULL;\n      \tstruct for_each_loose_cb cb_data = {\n11:  031a245247 ! 10:  ecbd9abef9 builtin/fsck: stop using `the_repository` when checking packed objects\n    @@ Commit message\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## builtin/fsck.c ##\n    -@@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n    +@@ builtin/fsck.c: static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n      }\n      \n      static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n    @@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n      \tif (!obj) {\n      \t\terrors_found |= ERROR_OBJECT;\n      \t\treturn error(_(\"%s: object corrupt or missing\"),\n    -@@ builtin/fsck.c: static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n    - \t}\n    - \tobj->flags &= ~(REACHABLE | SEEN);\n    - \tobj->flags |= HAS_OBJ;\n    --\treturn fsck_obj(the_repository, obj, buffer, size);\n    -+\treturn fsck_obj(repo, obj, buffer, size);\n    - }\n    - \n    - static int default_refs;\n     @@ builtin/fsck.c: int cmd_fsck(int argc,\n      \t\t\trepo_for_each_pack(repo, p) {\n      \t\t\t\t/* verify gives error messages itself */\n12:  5d61f5a545 ! 11:  9e246797c5 builtin/fsck: stop using `the_repository` when marking objects\n    @@ Commit message\n     \n      ## builtin/fsck.c ##\n     @@ builtin/fsck.c: static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n    - \n      static struct object_array pending;\n      \n    -+struct mark_object_data {\n    -+\tstruct repository *repo;\n    -+\tstruct object *parent;\n    -+};\n    -+\n      static int mark_object(struct object *obj, enum object_type type,\n     -\t\t       void *data, struct fsck_options *options UNUSED)\n    -+\t\t       void *cb_data, struct fsck_options *options UNUSED)\n    ++\t\t       void *data, struct fsck_options *options)\n      {\n    --\tstruct object *parent = data;\n    -+\tstruct mark_object_data *data = cb_data;\n    -+\tstruct object *parent = data->parent;\n    + \tstruct object *parent = data;\n      \n    - \t/*\n    - \t * The only case data is NULL or type is OBJ_ANY is when\n     @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type,\n      \t\treturn 0;\n      \tobj->flags |= REACHABLE;\n      \n     -\tif (is_promisor_object(the_repository, &obj->oid))\n    -+\tif (is_promisor_object(data->repo, &obj->oid))\n    ++\tif (is_promisor_object(options->repo, &obj->oid))\n      \t\t/*\n      \t\t * Further recursion does not need to be performed on this\n      \t\t * object since it is a promisor object (so it does not need to\n    @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type\n      \n      \tif (!(obj->flags & HAS_OBJ)) {\n     -\t\tif (parent && !odb_has_object(the_repository->objects, &obj->oid,\n    -+\t\tif (parent && !odb_has_object(data->repo->objects, &obj->oid,\n    ++\t\tif (parent && !odb_has_object(options->repo->objects, &obj->oid,\n      \t\t\t\t\t      HAS_OBJECT_RECHECK_PACKED)) {\n      \t\t\tprintf_ln(_(\"broken link from %7s %s\\n\"\n      \t\t\t\t    \"              to %7s %s\"),\n     @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type,\n    - \treturn 0;\n    - }\n      \n    --static void mark_object_reachable(struct object *obj)\n    -+static void mark_object_reachable(struct repository *repo, struct object *obj)\n    + static void mark_object_reachable(struct object *obj)\n      {\n     -\tmark_object(obj, OBJ_ANY, NULL, NULL);\n    -+\tstruct mark_object_data data = {\n    -+\t\t.repo = repo,\n    -+\t};\n    -+\tmark_object(obj, OBJ_ANY, &data, NULL);\n    ++\tmark_object(obj, OBJ_ANY, NULL, &fsck_walk_options);\n      }\n      \n    - static int traverse_one_object(struct repository *repo, struct object *obj)\n    - {\n    --\tint result = fsck_walk(repo, obj, obj, &fsck_walk_options);\n    -+\tstruct mark_object_data data = {\n    -+\t\t.repo = repo,\n    -+\t\t.parent = obj,\n    -+\t};\n    -+\tint result = fsck_walk(repo, obj, &data, &fsck_walk_options);\n    - \n    - \tif (obj->type == OBJ_TREE) {\n    - \t\tstruct tree *tree = (struct tree *)obj;\n    + static int traverse_one_object(struct object *obj)\n     @@ builtin/fsck.c: static int mark_used(struct object *obj, enum object_type type UNUSED,\n      \n      static int mark_unreachable_referents(const struct object_id *oid,\n    @@ builtin/fsck.c: static int mark_used(struct object *obj, enum object_type type U\n     +\t\t\t\t      void *data)\n      {\n     +\tstruct repository *repo = data;\n    - \tstruct fsck_options options = FSCK_OPTIONS_DEFAULT;\n    + \tstruct fsck_options options;\n     -\tstruct object *obj = lookup_object(the_repository, oid);\n    -+\tstruct object *obj = lookup_object(repo, oid);\n    ++\tstruct object *obj = lookup_object(data, oid);\n      \n      \tif (!obj || !(obj->flags & HAS_OBJ))\n      \t\treturn 0; /* not part of our original set */\n    @@ builtin/fsck.c: static int mark_unreachable_referents(const struct object_id *oi\n      \t\t\tobject_as_type(obj, type, 0);\n      \t}\n      \n    +-\tfsck_options_init(&options, the_repository, FSCK_OPTIONS_DEFAULT);\n    ++\tfsck_options_init(&options, repo, FSCK_OPTIONS_DEFAULT);\n      \toptions.walk = mark_used;\n    --\tfsck_walk(the_repository, obj, NULL, &options);\n    -+\tfsck_walk(repo, obj, NULL, &options);\n    + \tfsck_walk(obj, NULL, &options);\n      \tif (obj->type == OBJ_TREE)\n    - \t\tfree_tree_buffer((struct tree *)obj);\n    - \n     @@ builtin/fsck.c: static void check_connectivity(struct repository *repo)\n      \t\t * traversal.\n      \t\t */\n    @@ builtin/fsck.c: static void check_connectivity(struct repository *repo)\n      \t}\n      \n      \t/* Look up all the requirements, warn about missing objects.. */\n    -@@ builtin/fsck.c: static void fsck_handle_reflog_oid(struct repository *repo,\n    - \t\t\t\t\t\t     \"%s@{%\"PRItime\"}\",\n    - \t\t\t\t\t\t     refname, timestamp);\n    - \t\t\tobj->flags |= USED;\n    --\t\t\tmark_object_reachable(obj);\n    -+\t\t\tmark_object_reachable(repo, obj);\n    - \t\t} else if (!is_promisor_object(repo, oid)) {\n    - \t\t\terror(_(\"%s: invalid reflog entry %s\"),\n    - \t\t\t      refname, oid_to_hex(oid));\n    -@@ builtin/fsck.c: static int fsck_handle_ref(const struct reference *ref, void *cb_data)\n    - \tobj->flags |= USED;\n    - \tfsck_put_object_name(&fsck_walk_options,\n    - \t\t\t     ref->oid, \"%s\", ref->name);\n    --\tmark_object_reachable(obj);\n    -+\tmark_object_reachable(repo, obj);\n    - \n    - \treturn 0;\n    - }\n    -@@ builtin/fsck.c: static int fsck_cache_tree(struct repository *repo, struct cache_tree *it,\n    - \t\t}\n    - \t\tobj->flags |= USED;\n    - \t\tfsck_put_object_name(&fsck_walk_options, &it->oid, \":\");\n    --\t\tmark_object_reachable(obj);\n    -+\t\tmark_object_reachable(repo, obj);\n    - \t\tif (obj->type != OBJ_TREE)\n    - \t\t\terr |= objerror(obj, _(\"non-tree in cache-tree\"));\n    - \t}\n    -@@ builtin/fsck.c: static int fsck_resolve_undo(struct index_state *istate,\n    - \t\t\tobj->flags |= USED;\n    - \t\t\tfsck_put_object_name(&fsck_walk_options, &ru->oid[i],\n    - \t\t\t\t\t     \":(%d):%s\", i, path);\n    --\t\t\tmark_object_reachable(obj);\n    -+\t\t\tmark_object_reachable(istate->repo, obj);\n    - \t\t}\n    - \t}\n    - \treturn 0;\n    -@@ builtin/fsck.c: static void fsck_index(struct index_state *istate, const char *index_path,\n    - \t\t\t\t     \"%s:%s\",\n    - \t\t\t\t     is_current_worktree ? \"\" : index_path,\n    - \t\t\t\t     istate->cache[i]->name);\n    --\t\tmark_object_reachable(obj);\n    -+\t\tmark_object_reachable(istate->repo, obj);\n    - \t}\n    - \tif (istate->cache_tree)\n    - \t\tfsck_cache_tree(istate->repo, istate->cache_tree, index_path);\n     @@ builtin/fsck.c: static void fsck_index(struct index_state *istate, const char *index_path,\n      \n      static int mark_object_for_connectivity(const struct object_id *oid,\n13:  6842133df2 <  -:  ---------- fsck: provide repository in `struct fsck_report_object`\n14:  06a88b16cd ! 12:  066e60a2ca builtin/fsck: stop using `the_repository` in error reporting\n    @@ builtin/fsck.c: static const char *describe_object(const struct object_id *oid)\n      \n      \tif (type == OBJ_NONE)\n     -\t\ttype = odb_read_object_info(the_repository->objects,\n    -+\t\ttype = odb_read_object_info(repo->objects,\n    - \t\t\t\t\t    oid, NULL);\n    +-\t\t\t\t\t    oid, NULL);\n    ++\t\ttype = odb_read_object_info(repo->objects, oid, NULL);\n      \n      \tret = type_name(type);\n    + \tif (!ret)\n     @@ builtin/fsck.c: static const char *printable_type(const struct object_id *oid,\n      \treturn ret;\n      }\n    @@ builtin/fsck.c: static const char *printable_type(const struct object_id *oid,\n      \t\t   describe_object(&obj->oid), err);\n      \treturn -1;\n      }\n    + \n    +-static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n    ++static int fsck_objects_error_func(struct fsck_options *o,\n    + \t\t\t\t   void *fsck_report,\n    + \t\t\t\t   enum fsck_msg_type msg_type,\n    + \t\t\t\t   enum fsck_msg_id msg_id UNUSED,\n     @@ builtin/fsck.c: static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n      \tcase FSCK_WARN:\n      \t\t/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */\n      \t\tfprintf_ln(stderr, _(\"warning in %s %s: %s\"),\n     -\t\t\t   printable_type(oid, object_type),\n    -+\t\t\t   printable_type(report->repo, oid, object_type),\n    ++\t\t\t   printable_type(o->repo, oid, object_type),\n      \t\t\t   describe_object(oid), message);\n      \t\treturn 0;\n      \tcase FSCK_ERROR:\n      \t\t/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */\n      \t\tfprintf_ln(stderr, _(\"error in %s %s: %s\"),\n     -\t\t\t   printable_type(oid, object_type),\n    -+\t\t\t   printable_type(report->repo, oid, object_type),\n    ++\t\t\t   printable_type(o->repo, oid, object_type),\n      \t\t\t   describe_object(oid), message);\n      \t\treturn 1;\n      \tdefault:\n    @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type\n      \t\t/* ... these references to parent->fld are safe here */\n      \t\tprintf_ln(_(\"broken link from %7s %s\"),\n     -\t\t\t  printable_type(&parent->oid, parent->type),\n    -+\t\t\t  printable_type(data->repo, &parent->oid, parent->type),\n    ++\t\t\t  printable_type(options->repo, &parent->oid, parent->type),\n      \t\t\t  describe_object(&parent->oid));\n      \t\tprintf_ln(_(\"broken link from %7s %s\"),\n      \t\t\t  (type == OBJ_ANY ? _(\"unknown\") : type_name(type)),\n    @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type\n      \tif (type != OBJ_ANY && obj->type != type)\n      \t\t/* ... and the reference to parent is safe here */\n     -\t\tobjerror(parent, _(\"wrong object type in link\"));\n    -+\t\tobjerror(data->repo, parent, _(\"wrong object type in link\"));\n    ++\t\tobjerror(options->repo, parent, _(\"wrong object type in link\"));\n      \n      \tif (obj->flags & REACHABLE)\n      \t\treturn 0;\n    @@ builtin/fsck.c: static int mark_object(struct object *obj, enum object_type type\n      \t\t\tprintf_ln(_(\"broken link from %7s %s\\n\"\n      \t\t\t\t    \"              to %7s %s\"),\n     -\t\t\t\t  printable_type(&parent->oid, parent->type),\n    -+\t\t\t\t  printable_type(data->repo, &parent->oid, parent->type),\n    ++\t\t\t\t  printable_type(options->repo, &parent->oid, parent->type),\n      \t\t\t\t  describe_object(&parent->oid),\n     -\t\t\t\t  printable_type(&obj->oid, obj->type),\n    -+\t\t\t\t  printable_type(data->repo, &obj->oid, obj->type),\n    ++\t\t\t\t  printable_type(options->repo, &obj->oid, obj->type),\n      \t\t\t\t  describe_object(&obj->oid));\n      \t\t\terrors_found |= ERROR_REACHABLE;\n      \t\t}\n    @@ builtin/fsck.c: static void check_unreachable_object(struct repository *repo, st\n      \t\t\t\t  describe_object(&obj->oid));\n      \t\tif (write_lost_and_found) {\n      \t\t\tchar *filename = repo_git_path(repo, \"lost-found/%s/%s\",\n    -@@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n    +@@ builtin/fsck.c: static void check_connectivity(struct repository *repo)\n    + \t}\n    + }\n    + \n    +-static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n    ++static int fsck_obj(struct repository *repo,\n    ++\t\t    struct object *obj, void *buffer, unsigned long size)\n    + {\n    + \tint err;\n    + \n    +@@ builtin/fsck.c: static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n      \n      \tif (verbose)\n      \t\tfprintf_ln(stderr, _(\"Checking %s %s\"),\n    @@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n     +\t\t\t   printable_type(repo, &obj->oid, obj->type),\n      \t\t\t   describe_object(&obj->oid));\n      \n    - \tif (fsck_walk(repo, obj, NULL, &fsck_obj_options))\n    + \tif (fsck_walk(obj, NULL, &fsck_obj_options))\n     -\t\tobjerror(obj, _(\"broken links\"));\n     +\t\tobjerror(repo, obj, _(\"broken links\"));\n    - \terr = fsck_object(repo, obj, buffer, size, &fsck_obj_options);\n    + \terr = fsck_object(obj, buffer, size, &fsck_obj_options);\n      \tif (err)\n      \t\tgoto out;\n    -@@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n    +@@ builtin/fsck.c: static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n      \n      \t\tif (show_tags && tag->tagged) {\n      \t\t\tprintf_ln(_(\"tagged %s %s (%s) in %s\"),\n    @@ builtin/fsck.c: static int fsck_obj(struct repository *repo,\n      \t\t\t\t  describe_object(&tag->tagged->oid),\n      \t\t\t\t  tag->tag,\n      \t\t\t\t  describe_object(&tag->object.oid));\n    -@@ builtin/fsck.c: static int fsck_cache_tree(struct repository *repo, struct cache_tree *it,\n    +@@ builtin/fsck.c: static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n    + \t}\n    + \tobj->flags &= ~(REACHABLE | SEEN);\n    + \tobj->flags |= HAS_OBJ;\n    +-\treturn fsck_obj(obj, buffer, size);\n    ++\treturn fsck_obj(repo, obj, buffer, size);\n    + }\n    + \n    + static int default_refs;\n    +@@ builtin/fsck.c: static int fsck_loose(const struct object_id *oid, const char *path,\n    + \n    + \tobj->flags &= ~(REACHABLE | SEEN);\n    + \tobj->flags |= HAS_OBJ;\n    +-\tif (fsck_obj(obj, contents, size))\n    ++\tif (fsck_obj(data->repo, obj, contents, size))\n    + \t\terrors_found |= ERROR_OBJECT;\n    + \n    + \tif (!eaten)\n    +@@ builtin/fsck.c: static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const\n      \t\tfsck_put_object_name(&fsck_walk_options, &it->oid, \":\");\n    - \t\tmark_object_reachable(repo, obj);\n    + \t\tmark_object_reachable(obj);\n      \t\tif (obj->type != OBJ_TREE)\n     -\t\t\terr |= objerror(obj, _(\"non-tree in cache-tree\"));\n     +\t\t\terr |= objerror(repo, obj, _(\"non-tree in cache-tree\"));\n\n---\nbase-commit: 7ff1e8dc1e1680510c96e69965b3fa81372c5037\nchange-id: 20260320-b4-pks-fsck-without-the-repository-4ddc4c8ed61e\n\n"},{"id":"539734","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-1-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 01/12] fetch-pack: move fsck options into function scope","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:52Z","receivedAt":"2026-03-23T15:03:12Z","isPatch":true,"body":"When fetching a packfile, we optionally verify received objects via the\nfsck subsystem. The options for those consistency checks are declared in\nglobal scope without a good reason, and they are never cleaned up. So in\ncase the options are reused, they may accumulate more state over time.\n\nFurthermore, in subsequent changes we'll introduce a repository pointer\ninto the structure. Obviously though, we don't have a repository\navailable at static time, except for `the_repository`, which we don't\nwant to use here.\n\nRefactor the code to move the options into the respective functions and\nproperly manage their lifecycle.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n fetch-pack.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 6ecd468ef7..ec5abb92b5 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -51,7 +51,6 @@ static int server_supports_filtering;\n static int advertise_sid;\n static struct shallow_lock shallow_lock;\n static const char *alternate_shallow_file;\n-static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n static struct strbuf fsck_msg_types = STRBUF_INIT;\n static struct string_list uri_protocols = STRING_LIST_INIT_DUP;\n \n@@ -1100,6 +1099,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\t\t struct shallow_info *si,\n \t\t\t\t struct string_list *pack_lockfiles)\n {\n+\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n \tstruct repository *r = the_repository;\n \tstruct ref *ref = copy_ref_list(orig_ref);\n \tstruct object_id oid;\n@@ -1235,6 +1235,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\tdie(\"fsck failed\");\n \n  all_done:\n+\tfsck_options_clear(&fsck_options);\n \tif (negotiator)\n \t\tnegotiator->release(negotiator);\n \treturn ref;\n@@ -1654,6 +1655,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n \t\t\t\t    struct string_list *pack_lockfiles)\n {\n \tstruct repository *r = the_repository;\n+\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n \tstruct ref *ref = copy_ref_list(orig_ref);\n \tenum fetch_state state = FETCH_CHECK_LOCAL;\n \tstruct oidset common = OIDSET_INIT;\n@@ -1882,6 +1884,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n \tif (negotiator)\n \t\tnegotiator->release(negotiator);\n \n+\tfsck_options_clear(&fsck_options);\n \toidset_clear(&common);\n \treturn ref;\n }\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539736","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-2-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 02/12] fsck: initialize fsck options via a function","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:53Z","receivedAt":"2026-03-23T15:03:15Z","isPatch":true,"body":"We initialize the `struct fsck_options` via a set of macros, often in\nglobal scope. In the next commit though we're about to introduce a new\nrepository field to the options that must be initialized, and naturally\nwe don't have a repo other than `the_repository` available in this\nscope.\n\nRefactor the code to instead intrdouce a new `fsck_options_init()`\nfunction that initializes the options for us and move initialization\ninto function scope.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c           | 10 +++++++---\n builtin/index-pack.c     |  4 +++-\n builtin/mktag.c          |  3 ++-\n builtin/refs.c           |  4 +++-\n builtin/unpack-objects.c |  4 +++-\n fetch-pack.c             |  8 ++++++--\n fsck.c                   | 45 +++++++++++++++++++++++++++++++++++++++++++++\n fsck.h                   | 38 ++++++++++----------------------------\n object-file.c            |  3 ++-\n 9 files changed, 81 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 9bab32effe..59e3b0f7ac 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -42,8 +42,8 @@ static int check_full = 1;\n static int connectivity_only;\n static int check_strict;\n static int keep_cache_objects;\n-static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;\n-static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;\n+static struct fsck_options fsck_walk_options;\n+static struct fsck_options fsck_obj_options;\n static int errors_found;\n static int write_lost_and_found;\n static int verbose;\n@@ -224,7 +224,7 @@ static int mark_unreachable_referents(const struct object_id *oid,\n \t\t\t\t      struct object_info *oi UNUSED,\n \t\t\t\t      void *data UNUSED)\n {\n-\tstruct fsck_options options = FSCK_OPTIONS_DEFAULT;\n+\tstruct fsck_options options;\n \tstruct object *obj = lookup_object(the_repository, oid);\n \n \tif (!obj || !(obj->flags & HAS_OBJ))\n@@ -243,6 +243,7 @@ static int mark_unreachable_referents(const struct object_id *oid,\n \t\t\tobject_as_type(obj, type, 0);\n \t}\n \n+\tfsck_options_init(&options, FSCK_OPTIONS_DEFAULT);\n \toptions.walk = mark_used;\n \tfsck_walk(obj, NULL, &options);\n \tif (obj->type == OBJ_TREE)\n@@ -1004,7 +1005,10 @@ int cmd_fsck(int argc,\n \n \targc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);\n \n+\tfsck_options_init(&fsck_walk_options, FSCK_OPTIONS_DEFAULT);\n \tfsck_walk_options.walk = mark_object;\n+\n+\tfsck_options_init(&fsck_obj_options, FSCK_OPTIONS_DEFAULT);\n \tfsck_obj_options.walk = mark_used;\n \tfsck_obj_options.error_func = fsck_objects_error_func;\n \tif (check_strict)\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex d1e47279a8..c8d28bcf8e 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -136,7 +136,7 @@ static int nr_threads;\n static int from_stdin;\n static int strict;\n static int do_fsck_object;\n-static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n+static struct fsck_options fsck_options;\n static int verbose;\n static const char *progress_title;\n static int show_resolving_progress;\n@@ -1908,6 +1908,8 @@ int cmd_index_pack(int argc,\n \tshow_usage_if_asked(argc, argv, index_pack_usage);\n \n \tdisable_replace_refs();\n+\n+\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n \tfsck_options.walk = mark_link;\n \n \treset_pack_idx_option(&opts);\ndiff --git a/builtin/mktag.c b/builtin/mktag.c\nindex 7cf6e1230a..9f37f9dede 100644\n--- a/builtin/mktag.c\n+++ b/builtin/mktag.c\n@@ -16,7 +16,7 @@ static char const * const builtin_mktag_usage[] = {\n };\n static int option_strict = 1;\n \n-static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;\n+static struct fsck_options fsck_options;\n \n static int mktag_fsck_error_func(struct fsck_options *o UNUSED,\n \t\t\t\t void *fsck_report UNUSED,\n@@ -94,6 +94,7 @@ int cmd_mktag(int argc,\n \tif (strbuf_read(&buf, 0, 0) < 0)\n \t\tdie_errno(_(\"could not read from stdin\"));\n \n+\tfsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT);\n \tfsck_options.error_func = mktag_fsck_error_func;\n \tfsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,\n \t\t\t\t   FSCK_WARN);\ndiff --git a/builtin/refs.c b/builtin/refs.c\nindex 3064f888b2..1719ada549 100644\n--- a/builtin/refs.c\n+++ b/builtin/refs.c\n@@ -80,7 +80,7 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,\n static int cmd_refs_verify(int argc, const char **argv, const char *prefix,\n \t\t\t   struct repository *repo UNUSED)\n {\n-\tstruct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;\n+\tstruct fsck_options fsck_refs_options;\n \tstruct worktree **worktrees;\n \tconst char * const verify_usage[] = {\n \t\tREFS_VERIFY_USAGE,\n@@ -93,6 +93,8 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,\n \t};\n \tint ret = 0;\n \n+\tfsck_options_init(&fsck_refs_options, FSCK_OPTIONS_REFS);\n+\n \targc = parse_options(argc, argv, prefix, options, verify_usage, 0);\n \tif (argc)\n \t\tusage(_(\"'git refs verify' takes no arguments\"));\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 6fc64e9e4b..9e4bb9d25c 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -29,7 +29,7 @@ static unsigned int offset, len;\n static off_t consumed_bytes;\n static off_t max_input_size;\n static struct git_hash_ctx ctx;\n-static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;\n+static struct fsck_options fsck_options;\n static struct progress *progress;\n \n /*\n@@ -627,6 +627,8 @@ int cmd_unpack_objects(int argc,\n \n \tshow_usage_if_asked(argc, argv, unpack_usage);\n \n+\tfsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT);\n+\n \tfor (i = 1 ; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n \ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex ec5abb92b5..7339162368 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -1099,7 +1099,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\t\t struct shallow_info *si,\n \t\t\t\t struct string_list *pack_lockfiles)\n {\n-\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n+\tstruct fsck_options fsck_options = { 0 };\n \tstruct repository *r = the_repository;\n \tstruct ref *ref = copy_ref_list(orig_ref);\n \tstruct object_id oid;\n@@ -1228,6 +1228,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\talternate_shallow_file = setup_temporary_shallow(si->shallow);\n \t} else\n \t\talternate_shallow_file = NULL;\n+\n+\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n \tif (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,\n \t\t     &fsck_options.gitmodules_found))\n \t\tdie(_(\"git fetch-pack: fetch failed.\"));\n@@ -1655,7 +1657,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n \t\t\t\t    struct string_list *pack_lockfiles)\n {\n \tstruct repository *r = the_repository;\n-\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n+\tstruct fsck_options fsck_options;\n \tstruct ref *ref = copy_ref_list(orig_ref);\n \tenum fetch_state state = FETCH_CHECK_LOCAL;\n \tstruct oidset common = OIDSET_INIT;\n@@ -1673,6 +1675,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n \tstruct strvec index_pack_args = STRVEC_INIT;\n \tconst char *promisor_remote_config;\n \n+\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n+\n \tif (server_feature_v2(\"promisor-remote\", &promisor_remote_config))\n \t\tpromisor_remote_reply(promisor_remote_config, NULL);\n \ndiff --git a/fsck.c b/fsck.c\nindex 0f02cf8f77..1ff8208502 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -1380,6 +1380,51 @@ bool fsck_has_queued_checks(struct fsck_options *options)\n \t       !oidset_equal(&options->gitattributes_found, &options->gitattributes_done);\n }\n \n+void fsck_options_init(struct fsck_options *options,\n+\t\t       enum fsck_options_type type)\n+{\n+\tstatic const struct fsck_options defaults[] = {\n+\t\t[FSCK_OPTIONS_DEFAULT] = {\n+\t\t\t.skip_oids = OIDSET_INIT,\n+\t\t\t.gitmodules_found = OIDSET_INIT,\n+\t\t\t.gitmodules_done = OIDSET_INIT,\n+\t\t\t.gitattributes_found = OIDSET_INIT,\n+\t\t\t.gitattributes_done = OIDSET_INIT,\n+\t\t\t.error_func = fsck_objects_error_function\n+\t\t},\n+\t\t[FSCK_OPTIONS_STRICT] = {\n+\t\t\t.strict = 1,\n+\t\t\t.gitmodules_found = OIDSET_INIT,\n+\t\t\t.gitmodules_done = OIDSET_INIT,\n+\t\t\t.gitattributes_found = OIDSET_INIT,\n+\t\t\t.gitattributes_done = OIDSET_INIT,\n+\t\t\t.error_func = fsck_objects_error_function,\n+\t\t},\n+\t\t[FSCK_OPTIONS_MISSING_GITMODULES] = {\n+\t\t\t.strict = 1,\n+\t\t\t.gitmodules_found = OIDSET_INIT,\n+\t\t\t.gitmodules_done = OIDSET_INIT,\n+\t\t\t.gitattributes_found = OIDSET_INIT,\n+\t\t\t.gitattributes_done = OIDSET_INIT,\n+\t\t\t.error_func = fsck_objects_error_cb_print_missing_gitmodules,\n+\t\t},\n+\t\t[FSCK_OPTIONS_REFS] = {\n+\t\t\t.error_func = fsck_refs_error_function,\n+\t\t},\n+\t};\n+\n+\tswitch (type) {\n+\tcase FSCK_OPTIONS_DEFAULT:\n+\tcase FSCK_OPTIONS_STRICT:\n+\tcase FSCK_OPTIONS_MISSING_GITMODULES:\n+\tcase FSCK_OPTIONS_REFS:\n+\t\tmemcpy(options, &defaults[type], sizeof(*options));\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unknown fsck options type %d\", type);\n+\t}\n+}\n+\n void fsck_options_clear(struct fsck_options *options)\n {\n \tfree(options->msg_type);\ndiff --git a/fsck.h b/fsck.h\nindex 65ecbb7fe1..9c973b53b2 100644\n--- a/fsck.h\n+++ b/fsck.h\n@@ -180,34 +180,6 @@ struct fsck_options {\n \tkh_oid_map_t *object_names;\n };\n \n-#define FSCK_OPTIONS_DEFAULT { \\\n-\t.skip_oids = OIDSET_INIT, \\\n-\t.gitmodules_found = OIDSET_INIT, \\\n-\t.gitmodules_done = OIDSET_INIT, \\\n-\t.gitattributes_found = OIDSET_INIT, \\\n-\t.gitattributes_done = OIDSET_INIT, \\\n-\t.error_func = fsck_objects_error_function \\\n-}\n-#define FSCK_OPTIONS_STRICT { \\\n-\t.strict = 1, \\\n-\t.gitmodules_found = OIDSET_INIT, \\\n-\t.gitmodules_done = OIDSET_INIT, \\\n-\t.gitattributes_found = OIDSET_INIT, \\\n-\t.gitattributes_done = OIDSET_INIT, \\\n-\t.error_func = fsck_objects_error_function, \\\n-}\n-#define FSCK_OPTIONS_MISSING_GITMODULES { \\\n-\t.strict = 1, \\\n-\t.gitmodules_found = OIDSET_INIT, \\\n-\t.gitmodules_done = OIDSET_INIT, \\\n-\t.gitattributes_found = OIDSET_INIT, \\\n-\t.gitattributes_done = OIDSET_INIT, \\\n-\t.error_func = fsck_objects_error_cb_print_missing_gitmodules, \\\n-}\n-#define FSCK_REFS_OPTIONS_DEFAULT { \\\n-\t.error_func = fsck_refs_error_function, \\\n-}\n-\n /* descend in all linked child objects\n  * the return value is:\n  *    -1\terror in processing the object\n@@ -255,6 +227,16 @@ int fsck_finish(struct fsck_options *options);\n  */\n bool fsck_has_queued_checks(struct fsck_options *options);\n \n+enum fsck_options_type {\n+\tFSCK_OPTIONS_DEFAULT,\n+\tFSCK_OPTIONS_STRICT,\n+\tFSCK_OPTIONS_MISSING_GITMODULES,\n+\tFSCK_OPTIONS_REFS,\n+};\n+\n+void fsck_options_init(struct fsck_options *options,\n+\t\t       enum fsck_options_type type);\n+\n /*\n  * Clear the fsck_options struct, freeing any allocated memory.\n  */\ndiff --git a/object-file.c b/object-file.c\nindex c62e5496e0..186b2ff764 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1279,8 +1279,9 @@ static int index_mem(struct index_state *istate,\n \t\t}\n \t}\n \tif (flags & INDEX_FORMAT_CHECK) {\n-\t\tstruct fsck_options opts = FSCK_OPTIONS_DEFAULT;\n+\t\tstruct fsck_options opts;\n \n+\t\tfsck_options_init(&opts, FSCK_OPTIONS_DEFAULT);\n \t\topts.strict = 1;\n \t\topts.error_func = hash_format_check_report;\n \t\tif (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539737","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-3-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 03/12] fsck: store repository in fsck options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:54Z","receivedAt":"2026-03-23T15:03:18Z","isPatch":true,"body":"The fsck subsystem relies on `the_repository` quite a bit. While we\ncould of course explicitly pass a repository down the callchain, we\nalready have a `struct fsck_options` that we pass to almost all\nfunctions.\n\nExtend the options to also store the repository to make it readily\navailable.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c           | 8 ++++----\n builtin/index-pack.c     | 2 +-\n builtin/mktag.c          | 4 ++--\n builtin/refs.c           | 4 ++--\n builtin/unpack-objects.c | 4 ++--\n fetch-pack.c             | 4 ++--\n fsck.c                   | 3 +++\n fsck.h                   | 4 ++++\n object-file.c            | 2 +-\n 9 files changed, 21 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 59e3b0f7ac..990d836918 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -243,7 +243,7 @@ static int mark_unreachable_referents(const struct object_id *oid,\n \t\t\tobject_as_type(obj, type, 0);\n \t}\n \n-\tfsck_options_init(&options, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&options, the_repository, FSCK_OPTIONS_DEFAULT);\n \toptions.walk = mark_used;\n \tfsck_walk(obj, NULL, &options);\n \tif (obj->type == OBJ_TREE)\n@@ -987,7 +987,7 @@ static struct option fsck_opts[] = {\n int cmd_fsck(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo UNUSED)\n+\t     struct repository *repo)\n {\n \tstruct odb_source *source;\n \tstruct snapshot snap = {\n@@ -1005,10 +1005,10 @@ int cmd_fsck(int argc,\n \n \targc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);\n \n-\tfsck_options_init(&fsck_walk_options, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);\n \tfsck_walk_options.walk = mark_object;\n \n-\tfsck_options_init(&fsck_obj_options, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&fsck_obj_options, repo, FSCK_OPTIONS_DEFAULT);\n \tfsck_obj_options.walk = mark_used;\n \tfsck_obj_options.error_func = fsck_objects_error_func;\n \tif (check_strict)\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex c8d28bcf8e..e4129bd605 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1909,7 +1909,7 @@ int cmd_index_pack(int argc,\n \n \tdisable_replace_refs();\n \n-\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n+\tfsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);\n \tfsck_options.walk = mark_link;\n \n \treset_pack_idx_option(&opts);\ndiff --git a/builtin/mktag.c b/builtin/mktag.c\nindex 9f37f9dede..f40264a878 100644\n--- a/builtin/mktag.c\n+++ b/builtin/mktag.c\n@@ -75,7 +75,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)\n int cmd_mktag(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      struct repository *repo)\n {\n \tstatic struct option builtin_mktag_options[] = {\n \t\tOPT_BOOL(0, \"strict\", &option_strict,\n@@ -94,7 +94,7 @@ int cmd_mktag(int argc,\n \tif (strbuf_read(&buf, 0, 0) < 0)\n \t\tdie_errno(_(\"could not read from stdin\"));\n \n-\tfsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT);\n+\tfsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);\n \tfsck_options.error_func = mktag_fsck_error_func;\n \tfsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,\n \t\t\t\t   FSCK_WARN);\ndiff --git a/builtin/refs.c b/builtin/refs.c\nindex 1719ada549..e3125bc61b 100644\n--- a/builtin/refs.c\n+++ b/builtin/refs.c\n@@ -78,7 +78,7 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,\n }\n \n static int cmd_refs_verify(int argc, const char **argv, const char *prefix,\n-\t\t\t   struct repository *repo UNUSED)\n+\t\t\t   struct repository *repo)\n {\n \tstruct fsck_options fsck_refs_options;\n \tstruct worktree **worktrees;\n@@ -93,7 +93,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,\n \t};\n \tint ret = 0;\n \n-\tfsck_options_init(&fsck_refs_options, FSCK_OPTIONS_REFS);\n+\tfsck_options_init(&fsck_refs_options, repo, FSCK_OPTIONS_REFS);\n \n \targc = parse_options(argc, argv, prefix, options, verify_usage, 0);\n \tif (argc)\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 9e4bb9d25c..d863912b24 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -613,7 +613,7 @@ static void unpack_all(void)\n int cmd_unpack_objects(int argc,\n \t\t       const char **argv,\n \t\t       const char *prefix UNUSED,\n-\t\t       struct repository *repo UNUSED)\n+\t\t       struct repository *repo)\n {\n \tint i;\n \tstruct object_id oid;\n@@ -627,7 +627,7 @@ int cmd_unpack_objects(int argc,\n \n \tshow_usage_if_asked(argc, argv, unpack_usage);\n \n-\tfsck_options_init(&fsck_options, FSCK_OPTIONS_STRICT);\n+\tfsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);\n \n \tfor (i = 1 ; i < argc; i++) {\n \t\tconst char *arg = argv[i];\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 7339162368..84a21c5107 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -1229,7 +1229,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t} else\n \t\talternate_shallow_file = NULL;\n \n-\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n+\tfsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);\n \tif (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,\n \t\t     &fsck_options.gitmodules_found))\n \t\tdie(_(\"git fetch-pack: fetch failed.\"));\n@@ -1675,7 +1675,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n \tstruct strvec index_pack_args = STRVEC_INIT;\n \tconst char *promisor_remote_config;\n \n-\tfsck_options_init(&fsck_options, FSCK_OPTIONS_MISSING_GITMODULES);\n+\tfsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);\n \n \tif (server_feature_v2(\"promisor-remote\", &promisor_remote_config))\n \t\tpromisor_remote_reply(promisor_remote_config, NULL);\ndiff --git a/fsck.c b/fsck.c\nindex 1ff8208502..a05997703a 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -1381,6 +1381,7 @@ bool fsck_has_queued_checks(struct fsck_options *options)\n }\n \n void fsck_options_init(struct fsck_options *options,\n+\t\t       struct repository *repo,\n \t\t       enum fsck_options_type type)\n {\n \tstatic const struct fsck_options defaults[] = {\n@@ -1423,6 +1424,8 @@ void fsck_options_init(struct fsck_options *options,\n \tdefault:\n \t\tBUG(\"unknown fsck options type %d\", type);\n \t}\n+\n+\toptions->repo = repo;\n }\n \n void fsck_options_clear(struct fsck_options *options)\ndiff --git a/fsck.h b/fsck.h\nindex 9c973b53b2..e77935c8a9 100644\n--- a/fsck.h\n+++ b/fsck.h\n@@ -166,7 +166,10 @@ struct fsck_ref_report {\n \tconst char *path;\n };\n \n+struct repository;\n+\n struct fsck_options {\n+\tstruct repository *repo;\n \tfsck_walk_func walk;\n \tfsck_error error_func;\n \tunsigned strict;\n@@ -235,6 +238,7 @@ enum fsck_options_type {\n };\n \n void fsck_options_init(struct fsck_options *options,\n+\t\t       struct repository *repo,\n \t\t       enum fsck_options_type type);\n \n /*\ndiff --git a/object-file.c b/object-file.c\nindex 186b2ff764..24ed5d5577 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1281,7 +1281,7 @@ static int index_mem(struct index_state *istate,\n \tif (flags & INDEX_FORMAT_CHECK) {\n \t\tstruct fsck_options opts;\n \n-\t\tfsck_options_init(&opts, FSCK_OPTIONS_DEFAULT);\n+\t\tfsck_options_init(&opts, the_repository, FSCK_OPTIONS_DEFAULT);\n \t\topts.strict = 1;\n \t\topts.error_func = hash_format_check_report;\n \t\tif (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539738","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-4-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 04/12] fsck: drop USE_THE_REPOSITORY","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:55Z","receivedAt":"2026-03-23T15:03:21Z","isPatch":true,"body":"Stop using `the_repository` in \"fsck.c\" in favor of the repository that\nwe've already got available via `struct fsck_options`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n fsck.c | 28 +++++++++++++---------------\n 1 file changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex a05997703a..b72200c352 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -1,5 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n-\n #include \"git-compat-util.h\"\n #include \"date.h\"\n #include \"dir.h\"\n@@ -207,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)\n \t\t\tif (equal == len)\n \t\t\t\tdie(\"skiplist requires a path\");\n \t\t\toidset_parse_file(&options->skip_oids, buf + equal + 1,\n-\t\t\t\t\t  the_repository->hash_algo);\n+\t\t\t\t\t  options->repo->hash_algo);\n \t\t\tbuf += len + 1;\n \t\t\tcontinue;\n \t\t}\n@@ -360,7 +358,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op\n \tint res = 0;\n \tconst char *name;\n \n-\tif (repo_parse_tree(the_repository, tree))\n+\tif (repo_parse_tree(options->repo, tree))\n \t\treturn -1;\n \n \tname = fsck_get_object_name(options, &tree->object.oid);\n@@ -375,14 +373,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op\n \t\t\tcontinue;\n \n \t\tif (S_ISDIR(entry.mode)) {\n-\t\t\tobj = (struct object *)lookup_tree(the_repository, &entry.oid);\n+\t\t\tobj = (struct object *)lookup_tree(options->repo, &entry.oid);\n \t\t\tif (name && obj)\n \t\t\t\tfsck_put_object_name(options, &entry.oid, \"%s%s/\",\n \t\t\t\t\t\t     name, entry.path);\n \t\t\tresult = options->walk(obj, OBJ_TREE, data, options);\n \t\t}\n \t\telse if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {\n-\t\t\tobj = (struct object *)lookup_blob(the_repository, &entry.oid);\n+\t\t\tobj = (struct object *)lookup_blob(options->repo, &entry.oid);\n \t\t\tif (name && obj)\n \t\t\t\tfsck_put_object_name(options, &entry.oid, \"%s%s\",\n \t\t\t\t\t\t     name, entry.path);\n@@ -409,7 +407,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio\n \tint result;\n \tconst char *name;\n \n-\tif (repo_parse_commit(the_repository, commit))\n+\tif (repo_parse_commit(options->repo, commit))\n \t\treturn -1;\n \n \tname = fsck_get_object_name(options, &commit->object.oid);\n@@ -417,7 +415,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio\n \t\tfsck_put_object_name(options, get_commit_tree_oid(commit),\n \t\t\t\t     \"%s:\", name);\n \n-\tresult = options->walk((struct object *) repo_get_commit_tree(the_repository, commit),\n+\tresult = options->walk((struct object *) repo_get_commit_tree(options->repo, commit),\n \t\t\t       OBJ_TREE, data, options);\n \tif (result < 0)\n \t\treturn result;\n@@ -474,7 +472,7 @@ static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *optio\n {\n \tconst char *name = fsck_get_object_name(options, &tag->object.oid);\n \n-\tif (parse_tag(the_repository, tag))\n+\tif (parse_tag(options->repo, tag))\n \t\treturn -1;\n \tif (name)\n \t\tfsck_put_object_name(options, &tag->tagged->oid, \"%s\", name);\n@@ -487,7 +485,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)\n \t\treturn -1;\n \n \tif (obj->type == OBJ_NONE)\n-\t\tparse_object(the_repository, &obj->oid);\n+\t\tparse_object(options->repo, &obj->oid);\n \n \tswitch (obj->type) {\n \tcase OBJ_BLOB:\n@@ -970,14 +968,14 @@ static int fsck_commit(const struct object_id *oid,\n \n \tif (buffer >= buffer_end || !skip_prefix(buffer, \"tree \", &buffer))\n \t\treturn report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, \"invalid format - expected 'tree' line\");\n-\tif (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\\n') {\n+\tif (parse_oid_hex_algop(buffer, &tree_oid, &p, options->repo->hash_algo) || *p != '\\n') {\n \t\terr = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, \"invalid 'tree' line format - bad sha1\");\n \t\tif (err)\n \t\t\treturn err;\n \t}\n \tbuffer = p + 1;\n \twhile (buffer < buffer_end && skip_prefix(buffer, \"parent \", &buffer)) {\n-\t\tif (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\\n') {\n+\t\tif (parse_oid_hex_algop(buffer, &parent_oid, &p, options->repo->hash_algo) || *p != '\\n') {\n \t\t\terr = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, \"invalid 'parent' line format - bad sha1\");\n \t\t\tif (err)\n \t\t\t\treturn err;\n@@ -1044,7 +1042,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, \"invalid format - expected 'object' line\");\n \t\tgoto done;\n \t}\n-\tif (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\\n') {\n+\tif (parse_oid_hex_algop(buffer, tagged_oid, &p, options->repo->hash_algo) || *p != '\\n') {\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, \"invalid 'object' line format - bad sha1\");\n \t\tif (ret)\n \t\t\tgoto done;\n@@ -1336,9 +1334,9 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,\n \t\tif (oidset_contains(blobs_done, oid))\n \t\t\tcontinue;\n \n-\t\tbuf = odb_read_object(the_repository->objects, oid, &type, &size);\n+\t\tbuf = odb_read_object(options->repo->objects, oid, &type, &size);\n \t\tif (!buf) {\n-\t\t\tif (is_promisor_object(the_repository, oid))\n+\t\t\tif (is_promisor_object(options->repo, oid))\n \t\t\t\tcontinue;\n \t\t\tret |= report(options,\n \t\t\t\t      oid, OBJ_BLOB, msg_missing,\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539739","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-5-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 05/12] builtin/fsck: fix trivial dependence on `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:56Z","receivedAt":"2026-03-23T15:03:23Z","isPatch":true,"body":"We have a bunch of sites in \"builtin/fsck.c\" that depend on\n`the_repository` even though we already have a repository available, or\nin cases where we can trivially make it available.\n\nRefactor such sites to use the context-provided repository instead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 98 +++++++++++++++++++++++++++++-----------------------------\n 1 file changed, 49 insertions(+), 49 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 990d836918..59680e6daf 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -195,13 +195,13 @@ static int traverse_one_object(struct object *obj)\n \treturn result;\n }\n \n-static int traverse_reachable(void)\n+static int traverse_reachable(struct repository *repo)\n {\n \tstruct progress *progress = NULL;\n \tunsigned int nr = 0;\n \tint result = 0;\n \tif (show_progress)\n-\t\tprogress = start_delayed_progress(the_repository,\n+\t\tprogress = start_delayed_progress(repo,\n \t\t\t\t\t\t  _(\"Checking connectivity\"), 0);\n \twhile (pending.nr) {\n \t\tresult |= traverse_one_object(object_array_pop(&pending));\n@@ -255,7 +255,7 @@ static int mark_unreachable_referents(const struct object_id *oid,\n /*\n  * Check a single reachable object\n  */\n-static void check_reachable_object(struct object *obj)\n+static void check_reachable_object(struct repository *repo, struct object *obj)\n {\n \t/*\n \t * We obviously want the object to be parsed,\n@@ -263,9 +263,9 @@ static void check_reachable_object(struct object *obj)\n \t * do a full fsck\n \t */\n \tif (!(obj->flags & HAS_OBJ)) {\n-\t\tif (is_promisor_object(the_repository, &obj->oid))\n+\t\tif (is_promisor_object(repo, &obj->oid))\n \t\t\treturn;\n-\t\tif (has_object_pack(the_repository, &obj->oid))\n+\t\tif (has_object_pack(repo, &obj->oid))\n \t\t\treturn; /* it is in pack - forget about it */\n \t\tprintf_ln(_(\"missing %s %s\"),\n \t\t\t  printable_type(&obj->oid, obj->type),\n@@ -278,7 +278,7 @@ static void check_reachable_object(struct object *obj)\n /*\n  * Check a single unreachable object\n  */\n-static void check_unreachable_object(struct object *obj)\n+static void check_unreachable_object(struct repository *repo, struct object *obj)\n {\n \t/*\n \t * Missing unreachable object? Ignore it. It's not like\n@@ -318,19 +318,19 @@ static void check_unreachable_object(struct object *obj)\n \t\t\t\t  printable_type(&obj->oid, obj->type),\n \t\t\t\t  describe_object(&obj->oid));\n \t\tif (write_lost_and_found) {\n-\t\t\tchar *filename = repo_git_path(the_repository, \"lost-found/%s/%s\",\n+\t\t\tchar *filename = repo_git_path(repo, \"lost-found/%s/%s\",\n \t\t\t\tobj->type == OBJ_COMMIT ? \"commit\" : \"other\",\n \t\t\t\tdescribe_object(&obj->oid));\n \t\t\tFILE *f;\n \n-\t\t\tif (safe_create_leading_directories_const(the_repository, filename)) {\n+\t\t\tif (safe_create_leading_directories_const(repo, filename)) {\n \t\t\t\terror(_(\"could not create lost-found\"));\n \t\t\t\tfree(filename);\n \t\t\t\treturn;\n \t\t\t}\n \t\t\tf = xfopen(filename, \"w\");\n \t\t\tif (obj->type == OBJ_BLOB) {\n-\t\t\t\tif (odb_stream_blob_to_fd(the_repository->objects, fileno(f),\n+\t\t\t\tif (odb_stream_blob_to_fd(repo->objects, fileno(f),\n \t\t\t\t\t\t\t  &obj->oid, NULL, 1))\n \t\t\t\t\tdie_errno(_(\"could not write '%s'\"), filename);\n \t\t\t} else\n@@ -350,23 +350,23 @@ static void check_unreachable_object(struct object *obj)\n \t */\n }\n \n-static void check_object(struct object *obj)\n+static void check_object(struct repository *repo, struct object *obj)\n {\n \tif (verbose)\n \t\tfprintf_ln(stderr, _(\"Checking %s\"), describe_object(&obj->oid));\n \n \tif (obj->flags & REACHABLE)\n-\t\tcheck_reachable_object(obj);\n+\t\tcheck_reachable_object(repo, obj);\n \telse\n-\t\tcheck_unreachable_object(obj);\n+\t\tcheck_unreachable_object(repo, obj);\n }\n \n-static void check_connectivity(void)\n+static void check_connectivity(struct repository *repo)\n {\n \tint i, max;\n \n \t/* Traverse the pending reachable objects */\n-\ttraverse_reachable();\n+\ttraverse_reachable(repo);\n \n \t/*\n \t * With --connectivity-only, we won't have actually opened and marked\n@@ -384,20 +384,20 @@ static void check_connectivity(void)\n \t\t * and ignore any that weren't present in our earlier\n \t\t * traversal.\n \t\t */\n-\t\todb_for_each_object(the_repository->objects, NULL,\n+\t\todb_for_each_object(repo->objects, NULL,\n \t\t\t\t    mark_unreachable_referents, NULL, 0);\n \t}\n \n \t/* Look up all the requirements, warn about missing objects.. */\n-\tmax = get_max_object_index(the_repository);\n+\tmax = get_max_object_index(repo);\n \tif (verbose)\n \t\tfprintf_ln(stderr, _(\"Checking connectivity (%d objects)\"), max);\n \n \tfor (i = 0; i < max; i++) {\n-\t\tstruct object *obj = get_indexed_object(the_repository, i);\n+\t\tstruct object *obj = get_indexed_object(repo, i);\n \n \t\tif (obj)\n-\t\t\tcheck_object(obj);\n+\t\t\tcheck_object(repo, obj);\n \t}\n }\n \n@@ -770,7 +770,7 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)\n \treturn 0;\n }\n \n-static void fsck_source(struct odb_source *source)\n+static void fsck_source(struct repository *repo, struct odb_source *source)\n {\n \tstruct progress *progress = NULL;\n \tstruct for_each_loose_cb cb_data = {\n@@ -781,7 +781,7 @@ static void fsck_source(struct odb_source *source)\n \t\tfprintf_ln(stderr, _(\"Checking object directory\"));\n \n \tif (show_progress)\n-\t\tprogress = start_progress(the_repository,\n+\t\tprogress = start_progress(repo,\n \t\t\t\t\t  _(\"Checking object directories\"), 256);\n \n \tfor_each_loose_file_in_source(source, fsck_loose,\n@@ -790,7 +790,7 @@ static void fsck_source(struct odb_source *source)\n \tstop_progress(&progress);\n }\n \n-static int fsck_cache_tree(struct cache_tree *it, const char *index_path)\n+static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const char *index_path)\n {\n \tint i;\n \tint err = 0;\n@@ -799,7 +799,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)\n \t\tfprintf_ln(stderr, _(\"Checking cache tree of %s\"), index_path);\n \n \tif (0 <= it->entry_count) {\n-\t\tstruct object *obj = parse_object(the_repository, &it->oid);\n+\t\tstruct object *obj = parse_object(repo, &it->oid);\n \t\tif (!obj) {\n \t\t\terror(_(\"%s: invalid sha1 pointer in cache-tree of %s\"),\n \t\t\t      oid_to_hex(&it->oid), index_path);\n@@ -813,7 +813,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)\n \t\t\terr |= objerror(obj, _(\"non-tree in cache-tree\"));\n \t}\n \tfor (i = 0; i < it->subtree_nr; i++)\n-\t\terr |= fsck_cache_tree(it->down[i]->cache_tree, index_path);\n+\t\terr |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path);\n \treturn err;\n }\n \n@@ -839,7 +839,7 @@ static int fsck_resolve_undo(struct index_state *istate,\n \t\t\tif (!ru->mode[i] || !S_ISREG(ru->mode[i]))\n \t\t\t\tcontinue;\n \n-\t\t\tobj = parse_object(the_repository, &ru->oid[i]);\n+\t\t\tobj = parse_object(istate->repo, &ru->oid[i]);\n \t\t\tif (!obj) {\n \t\t\t\terror(_(\"%s: invalid sha1 pointer in resolve-undo of %s\"),\n \t\t\t\t      oid_to_hex(&ru->oid[i]),\n@@ -871,7 +871,7 @@ static void fsck_index(struct index_state *istate, const char *index_path,\n \t\tmode = istate->cache[i]->ce_mode;\n \t\tif (S_ISGITLINK(mode))\n \t\t\tcontinue;\n-\t\tblob = lookup_blob(the_repository,\n+\t\tblob = lookup_blob(istate->repo,\n \t\t\t\t   &istate->cache[i]->oid);\n \t\tif (!blob)\n \t\t\tcontinue;\n@@ -884,7 +884,7 @@ static void fsck_index(struct index_state *istate, const char *index_path,\n \t\tmark_object_reachable(obj);\n \t}\n \tif (istate->cache_tree)\n-\t\tfsck_cache_tree(istate->cache_tree, index_path);\n+\t\tfsck_cache_tree(istate->repo, istate->cache_tree, index_path);\n \tfsck_resolve_undo(istate, index_path);\n }\n \n@@ -907,7 +907,7 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress)\n \tif (show_progress) {\n \t\trepo_for_each_pack(r, p)\n \t\t\tpack_count++;\n-\t\tprogress = start_delayed_progress(the_repository,\n+\t\tprogress = start_delayed_progress(r,\n \t\t\t\t\t\t  \"Verifying reverse pack-indexes\", pack_count);\n \t\tpack_count = 0;\n \t}\n@@ -1027,11 +1027,11 @@ int cmd_fsck(int argc,\n \tif (name_objects)\n \t\tfsck_enable_object_names(&fsck_walk_options);\n \n-\trepo_config(the_repository, git_fsck_config, &fsck_obj_options);\n-\tprepare_repo_settings(the_repository);\n+\trepo_config(repo, git_fsck_config, &fsck_obj_options);\n+\tprepare_repo_settings(repo);\n \n \tif (check_references)\n-\t\tfsck_refs(the_repository);\n+\t\tfsck_refs(repo);\n \n \t/*\n \t * Take a snapshot of the refs before walking objects to avoid looking\n@@ -1042,15 +1042,15 @@ int cmd_fsck(int argc,\n \tsnapshot_refs(&snap, argc, argv);\n \n \t/* Ensure we get a \"fresh\" view of the odb */\n-\todb_reprepare(the_repository->objects);\n+\todb_reprepare(repo->objects);\n \n \tif (connectivity_only) {\n-\t\todb_for_each_object(the_repository->objects, NULL,\n+\t\todb_for_each_object(repo->objects, NULL,\n \t\t\t\t    mark_object_for_connectivity, NULL, 0);\n \t} else {\n-\t\todb_prepare_alternates(the_repository->objects);\n-\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n-\t\t\tfsck_source(source);\n+\t\todb_prepare_alternates(repo->objects);\n+\t\tfor (source = repo->objects->sources; source; source = source->next)\n+\t\t\tfsck_source(repo, source);\n \n \t\tif (check_full) {\n \t\t\tstruct packed_git *p;\n@@ -1058,19 +1058,19 @@ int cmd_fsck(int argc,\n \t\t\tstruct progress *progress = NULL;\n \n \t\t\tif (show_progress) {\n-\t\t\t\trepo_for_each_pack(the_repository, p) {\n+\t\t\t\trepo_for_each_pack(repo, p) {\n \t\t\t\t\tif (open_pack_index(p))\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\ttotal += p->num_objects;\n \t\t\t\t}\n \n-\t\t\t\tprogress = start_progress(the_repository,\n+\t\t\t\tprogress = start_progress(repo,\n \t\t\t\t\t\t\t  _(\"Checking objects\"), total);\n \t\t\t}\n \n-\t\t\trepo_for_each_pack(the_repository, p) {\n+\t\t\trepo_for_each_pack(repo, p) {\n \t\t\t\t/* verify gives error messages itself */\n-\t\t\t\tif (verify_pack(the_repository,\n+\t\t\t\tif (verify_pack(repo,\n \t\t\t\t\t\tp, fsck_obj_buffer,\n \t\t\t\t\t\tprogress, count))\n \t\t\t\t\terrors_found |= ERROR_PACK;\n@@ -1104,7 +1104,7 @@ int cmd_fsck(int argc,\n \t\tfor (p = worktrees; *p; p++) {\n \t\t\tstruct worktree *wt = *p;\n \t\t\tstruct index_state istate =\n-\t\t\t\tINDEX_STATE_INIT(the_repository);\n+\t\t\t\tINDEX_STATE_INIT(repo);\n \t\t\tchar *path, *wt_gitdir;\n \n \t\t\t/*\n@@ -1125,17 +1125,17 @@ int cmd_fsck(int argc,\n \t\tfree_worktrees(worktrees);\n \t}\n \n-\terrors_found |= check_pack_rev_indexes(the_repository, show_progress);\n-\tif (verify_bitmap_files(the_repository))\n+\terrors_found |= check_pack_rev_indexes(repo, show_progress);\n+\tif (verify_bitmap_files(repo))\n \t\terrors_found |= ERROR_BITMAP;\n \n-\tcheck_connectivity();\n+\tcheck_connectivity(repo);\n \n-\tif (the_repository->settings.core_commit_graph) {\n+\tif (repo->settings.core_commit_graph) {\n \t\tstruct child_process commit_graph_verify = CHILD_PROCESS_INIT;\n \n-\t\todb_prepare_alternates(the_repository->objects);\n-\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n+\t\todb_prepare_alternates(repo->objects);\n+\t\tfor (source = repo->objects->sources; source; source = source->next) {\n \t\t\tchild_process_init(&commit_graph_verify);\n \t\t\tcommit_graph_verify.git_cmd = 1;\n \t\t\tstrvec_pushl(&commit_graph_verify.args, \"commit-graph\",\n@@ -1149,11 +1149,11 @@ int cmd_fsck(int argc,\n \t\t}\n \t}\n \n-\tif (the_repository->settings.core_multi_pack_index) {\n+\tif (repo->settings.core_multi_pack_index) {\n \t\tstruct child_process midx_verify = CHILD_PROCESS_INIT;\n \n-\t\todb_prepare_alternates(the_repository->objects);\n-\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n+\t\todb_prepare_alternates(repo->objects);\n+\t\tfor (source = repo->objects->sources; source; source = source->next) {\n \t\t\tchild_process_init(&midx_verify);\n \t\t\tmidx_verify.git_cmd = 1;\n \t\t\tstrvec_pushl(&midx_verify.args, \"multi-pack-index\",\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539740","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-6-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 06/12] builtin/fsck: stop using `the_repository` when snapshotting refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:57Z","receivedAt":"2026-03-23T15:03:25Z","isPatch":true,"body":"We depedn on `the_repository` when snapshotting refs. Refactor this to\nuse a context-provided repository instead that is injected via the\n`struct snapshot_ref_data`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 33 ++++++++++++++++++++++-----------\n 1 file changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 59680e6daf..edbff16add 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -533,14 +533,20 @@ struct snapshot {\n \t/* TODO: Consider also snapshotting the index of each worktree. */\n };\n \n+struct snapshot_ref_data {\n+\tstruct repository *repo;\n+\tstruct snapshot *snap;\n+};\n+\n static int snapshot_ref(const struct reference *ref, void *cb_data)\n {\n-\tstruct snapshot *snap = cb_data;\n+\tstruct snapshot_ref_data *data = cb_data;\n+\tstruct snapshot *snap = data->snap;\n \tstruct object *obj;\n \n-\tobj = parse_object(the_repository, ref->oid);\n+\tobj = parse_object(data->repo, ref->oid);\n \tif (!obj) {\n-\t\tif (is_promisor_object(the_repository, ref->oid)) {\n+\t\tif (is_promisor_object(data->repo, ref->oid)) {\n \t\t\t/*\n \t\t\t * Increment default_refs anyway, because this is a\n \t\t\t * valid ref.\n@@ -581,11 +587,16 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)\n \treturn 0;\n }\n \n-static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n+static void snapshot_refs(struct repository *repo,\n+\t\t\t  struct snapshot *snap, int argc, const char **argv)\n {\n \tstruct refs_for_each_ref_options opts = {\n \t\t.flags = REFS_FOR_EACH_INCLUDE_BROKEN,\n \t};\n+\tstruct snapshot_ref_data data = {\n+\t\t.repo = repo,\n+\t\t.snap = snap,\n+\t};\n \tstruct worktree **worktrees, **p;\n \tconst char *head_points_at;\n \tstruct object_id head_oid;\n@@ -593,13 +604,13 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n \tfor (int i = 0; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n \t\tstruct object_id oid;\n-\t\tif (!repo_get_oid(the_repository, arg, &oid)) {\n+\t\tif (!repo_get_oid(repo, arg, &oid)) {\n \t\t\tstruct reference ref = {\n \t\t\t\t.name = arg,\n \t\t\t\t.oid = &oid,\n \t\t\t};\n \n-\t\t\tsnapshot_ref(&ref, snap);\n+\t\t\tsnapshot_ref(&ref, &data);\n \t\t\tcontinue;\n \t\t}\n \t\terror(_(\"invalid parameter: expected sha1, got '%s'\"), arg);\n@@ -611,8 +622,8 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n \t\treturn;\n \t}\n \n-\trefs_for_each_ref_ext(get_main_ref_store(the_repository),\n-\t\t\t      snapshot_ref, snap, &opts);\n+\trefs_for_each_ref_ext(get_main_ref_store(repo),\n+\t\t\t      snapshot_ref, &data, &opts);\n \n \tworktrees = get_worktrees();\n \tfor (p = worktrees; *p; p++) {\n@@ -621,7 +632,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n \n \t\tstrbuf_worktree_ref(wt, &refname, \"HEAD\");\n \n-\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),\n+\t\thead_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo),\n \t\t\t\t\t\t\t refname.buf, 0, &head_oid, NULL);\n \n \t\tif (head_points_at && !is_null_oid(&head_oid)) {\n@@ -630,7 +641,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)\n \t\t\t\t.oid = &head_oid,\n \t\t\t};\n \n-\t\t\tsnapshot_ref(&ref, snap);\n+\t\t\tsnapshot_ref(&ref, &data);\n \t\t}\n \t\tstrbuf_release(&refname);\n \n@@ -1039,7 +1050,7 @@ int cmd_fsck(int argc,\n \t * objects. We can still walk over new objects that are added during the\n \t * execution of fsck but won't miss any objects that were reachable.\n \t */\n-\tsnapshot_refs(&snap, argc, argv);\n+\tsnapshot_refs(repo, &snap, argc, argv);\n \n \t/* Ensure we get a \"fresh\" view of the odb */\n \todb_reprepare(repo->objects);\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539741","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-7-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 07/12] builtin/fsck: stop using `the_repository` when checking refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:58Z","receivedAt":"2026-03-23T15:03:28Z","isPatch":true,"body":"We implicitly rely on `the_repository` when checking refs. Refactor this\nto instead inject the repository via the callback payload.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex edbff16add..efc60862ae 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -574,11 +574,12 @@ static int snapshot_ref(const struct reference *ref, void *cb_data)\n \treturn 0;\n }\n \n-static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)\n+static int fsck_handle_ref(const struct reference *ref, void *cb_data)\n {\n+\tstruct repository *repo = cb_data;\n \tstruct object *obj;\n \n-\tobj = parse_object(the_repository, ref->oid);\n+\tobj = parse_object(repo, ref->oid);\n \tobj->flags |= USED;\n \tfsck_put_object_name(&fsck_walk_options,\n \t\t\t     ref->oid, \"%s\", ref->name);\n@@ -665,7 +666,7 @@ static void free_snapshot_refs(struct snapshot *snap)\n \tfree(snap->ref);\n }\n \n-static void process_refs(struct snapshot *snap)\n+static void process_refs(struct repository *repo, struct snapshot *snap)\n {\n \tstruct worktree **worktrees, **p;\n \n@@ -674,7 +675,7 @@ static void process_refs(struct snapshot *snap)\n \t\t\t.name = snap->ref[i].refname,\n \t\t\t.oid = &snap->ref[i].oid,\n \t\t};\n-\t\tfsck_handle_ref(&ref, NULL);\n+\t\tfsck_handle_ref(&ref, repo);\n \t}\n \n \tif (include_reflogs) {\n@@ -1095,7 +1096,7 @@ int cmd_fsck(int argc,\n \t}\n \n \t/* Process the snapshotted refs and the reflogs. */\n-\tprocess_refs(&snap);\n+\tprocess_refs(repo, &snap);\n \n \t/* If not given any explicit objects, process index files too. */\n \tif (!argc)\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539742","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-8-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 08/12] builtin/fsck: stop using `the_repository` when checking reflogs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:02:59Z","receivedAt":"2026-03-23T15:03:30Z","isPatch":true,"body":"We implicitly rely on `the_repository` when checking reflogs. Refactor\nthis to instead inject the repository via the callback payload.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 24 ++++++++++++++----------\n 1 file changed, 14 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex efc60862ae..be9dbba2da 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -468,13 +468,14 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n \n static int default_refs;\n \n-static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\ttimestamp_t timestamp)\n+static void fsck_handle_reflog_oid(struct repository *repo,\n+\t\t\t\t   const char *refname, struct object_id *oid,\n+\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct object *obj;\n \n \tif (!is_null_oid(oid)) {\n-\t\tobj = lookup_object(the_repository, oid);\n+\t\tobj = lookup_object(repo, oid);\n \t\tif (obj && (obj->flags & HAS_OBJ)) {\n \t\t\tif (timestamp)\n \t\t\t\tfsck_put_object_name(&fsck_walk_options, oid,\n@@ -482,7 +483,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\t\t\t\t     refname, timestamp);\n \t\t\tobj->flags |= USED;\n \t\t\tmark_object_reachable(obj);\n-\t\t} else if (!is_promisor_object(the_repository, oid)) {\n+\t\t} else if (!is_promisor_object(repo, oid)) {\n \t\t\terror(_(\"%s: invalid reflog entry %s\"),\n \t\t\t      refname, oid_to_hex(oid));\n \t\t\terrors_found |= ERROR_REACHABLE;\n@@ -494,8 +495,10 @@ static int fsck_handle_reflog_ent(const char *refname,\n \t\t\t\t  struct object_id *ooid, struct object_id *noid,\n \t\t\t\t  const char *email UNUSED,\n \t\t\t\t  timestamp_t timestamp, int tz UNUSED,\n-\t\t\t\t  const char *message UNUSED, void *cb_data UNUSED)\n+\t\t\t\t  const char *message UNUSED, void *cb_data)\n {\n+\tstruct repository *repo = cb_data;\n+\n \tif (now && timestamp > now)\n \t\treturn 0;\n \n@@ -503,19 +506,20 @@ static int fsck_handle_reflog_ent(const char *refname,\n \t\tfprintf_ln(stderr, _(\"Checking reflog %s->%s\"),\n \t\t\t   oid_to_hex(ooid), oid_to_hex(noid));\n \n-\tfsck_handle_reflog_oid(refname, ooid, 0);\n-\tfsck_handle_reflog_oid(refname, noid, timestamp);\n+\tfsck_handle_reflog_oid(repo, refname, ooid, 0);\n+\tfsck_handle_reflog_oid(repo, refname, noid, timestamp);\n \treturn 0;\n }\n \n static int fsck_handle_reflog(const char *logname, void *cb_data)\n {\n \tstruct strbuf refname = STRBUF_INIT;\n+\tstruct worktree *wt = cb_data;\n \n-\tstrbuf_worktree_ref(cb_data, &refname, logname);\n-\trefs_for_each_reflog_ent(get_main_ref_store(the_repository),\n+\tstrbuf_worktree_ref(wt, &refname, logname);\n+\trefs_for_each_reflog_ent(get_main_ref_store(wt->repo),\n \t\t\t\t refname.buf, fsck_handle_reflog_ent,\n-\t\t\t\t NULL);\n+\t\t\t\t wt->repo);\n \tstrbuf_release(&refname);\n \treturn 0;\n }\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539743","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-9-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 09/12] builtin/fsck: stop using `the_repository` with loose objects","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:03:00Z","receivedAt":"2026-03-23T15:03:34Z","isPatch":true,"body":"We depend on `the_repository` when performing consistency checks for\nloose objects. Refactor this to use a context-provided repository\ninstead that is injected via the `struct for_each_loose_cb`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex be9dbba2da..e8bdec7cd0 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -711,27 +711,28 @@ static void process_refs(struct repository *repo, struct snapshot *snap)\n \t}\n }\n \n-struct for_each_loose_cb\n-{\n+struct for_each_loose_cb {\n+\tstruct repository *repo;\n \tstruct progress *progress;\n };\n \n static int fsck_loose(const struct object_id *oid, const char *path,\n-\t\t      void *data UNUSED)\n+\t\t      void *cb_data)\n {\n+\tstruct for_each_loose_cb *data = cb_data;\n \tstruct object *obj;\n \tenum object_type type = OBJ_NONE;\n \tunsigned long size;\n \tvoid *contents = NULL;\n \tint eaten;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n-\tstruct object_id real_oid = *null_oid(the_hash_algo);\n+\tstruct object_id real_oid = *null_oid(data->repo->hash_algo);\n \tint err = 0;\n \n \toi.sizep = &size;\n \toi.typep = &type;\n \n-\tif (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) {\n+\tif (read_loose_object(data->repo, path, oid, &real_oid, &contents, &oi) < 0) {\n \t\tif (contents && !oideq(&real_oid, oid))\n \t\t\terr = error(_(\"%s: hash-path mismatch, found at: %s\"),\n \t\t\t\t    oid_to_hex(&real_oid), path);\n@@ -748,7 +749,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,\n \tif (!contents && type != OBJ_BLOB)\n \t\tBUG(\"read_loose_object streamed a non-blob\");\n \n-\tobj = parse_object_buffer(the_repository, oid, type, size,\n+\tobj = parse_object_buffer(data->repo, oid, type, size,\n \t\t\t\t  contents, &eaten);\n \n \tif (!obj) {\n@@ -790,6 +791,7 @@ static void fsck_source(struct repository *repo, struct odb_source *source)\n {\n \tstruct progress *progress = NULL;\n \tstruct for_each_loose_cb cb_data = {\n+\t\t.repo = source->odb->repo,\n \t\t.progress = progress,\n \t};\n \n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539744","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-10-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 10/12] builtin/fsck: stop using `the_repository` when checking packed objects","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:03:01Z","receivedAt":"2026-03-23T15:03:36Z","isPatch":true,"body":"We implicitly rely on `the_repository` when checking objects part of a\npackfile. These objects are iterated over via `verify_pack()`, which is\nprovided by the packfile subsystem, and a callback function is then\ninvoked for each of the objects in that specific pack.\n\nUnfortunately, it is not possible to provide a payload to the callback\nfunction. Refactor `verify_pack()` to accept a payload that is passed\nthrough to the callback so that we can inject the repository and get rid\nof the use of `the_repository`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 11 ++++++-----\n pack-check.c   |  7 ++++---\n pack.h         |  9 +++++++--\n 3 files changed, 17 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex e8bdec7cd0..22ca1200a2 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -447,15 +447,16 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n }\n \n static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n-\t\t\t   unsigned long size, void *buffer, int *eaten)\n+\t\t\t   unsigned long size, void *buffer, int *eaten, void *cb_data)\n {\n+\tstruct repository *repo = cb_data;\n+\tstruct object *obj;\n+\n \t/*\n \t * Note, buffer may be NULL if type is OBJ_BLOB. See\n \t * verify_packfile(), data_valid variable for details.\n \t */\n-\tstruct object *obj;\n-\tobj = parse_object_buffer(the_repository, oid, type, size, buffer,\n-\t\t\t\t  eaten);\n+\tobj = parse_object_buffer(repo, oid, type, size, buffer, eaten);\n \tif (!obj) {\n \t\terrors_found |= ERROR_OBJECT;\n \t\treturn error(_(\"%s: object corrupt or missing\"),\n@@ -1089,7 +1090,7 @@ int cmd_fsck(int argc,\n \t\t\trepo_for_each_pack(repo, p) {\n \t\t\t\t/* verify gives error messages itself */\n \t\t\t\tif (verify_pack(repo,\n-\t\t\t\t\t\tp, fsck_obj_buffer,\n+\t\t\t\t\t\tp, fsck_obj_buffer, repo,\n \t\t\t\t\t\tprogress, count))\n \t\t\t\t\terrors_found |= ERROR_PACK;\n \t\t\t\tcount += p->num_objects;\ndiff --git a/pack-check.c b/pack-check.c\nindex 7378c80730..79992bb509 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -53,6 +53,7 @@ static int verify_packfile(struct repository *r,\n \t\t\t   struct packed_git *p,\n \t\t\t   struct pack_window **w_curs,\n \t\t\t   verify_fn fn,\n+\t\t\t   void *fn_data,\n \t\t\t   struct progress *progress, uint32_t base_count)\n \n {\n@@ -161,7 +162,7 @@ static int verify_packfile(struct repository *r,\n \t\t\t\t    oid_to_hex(&oid), p->pack_name);\n \t\telse if (fn) {\n \t\t\tint eaten = 0;\n-\t\t\terr |= fn(&oid, type, size, data, &eaten);\n+\t\t\terr |= fn(&oid, type, size, data, &eaten, fn_data);\n \t\t\tif (eaten)\n \t\t\t\tdata = NULL;\n \t\t}\n@@ -192,7 +193,7 @@ int verify_pack_index(struct packed_git *p)\n \treturn err;\n }\n \n-int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,\n+int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, void *fn_data,\n \t\tstruct progress *progress, uint32_t base_count)\n {\n \tint err = 0;\n@@ -202,7 +203,7 @@ int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,\n \tif (!p->index_data)\n \t\treturn -1;\n \n-\terr |= verify_packfile(r, p, &w_curs, fn, progress, base_count);\n+\terr |= verify_packfile(r, p, &w_curs, fn, fn_data, progress, base_count);\n \tunuse_pack(&w_curs);\n \n \treturn err;\ndiff --git a/pack.h b/pack.h\nindex ec76472e49..1cde92082b 100644\n--- a/pack.h\n+++ b/pack.h\n@@ -85,7 +85,11 @@ struct pack_idx_entry {\n \n struct progress;\n /* Note, the data argument could be NULL if object type is blob */\n-typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*);\n+typedef int (*verify_fn)(const struct object_id *oid,\n+\t\t\t enum object_type type,\n+\t\t\t unsigned long size,\n+\t\t\t void *buffer, int *eaten,\n+\t\t\t void *fn_data);\n \n const char *write_idx_file(struct repository *repo,\n \t\t\t   const char *index_name,\n@@ -95,7 +99,8 @@ const char *write_idx_file(struct repository *repo,\n \t\t\t   const unsigned char *sha1);\n int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);\n int verify_pack_index(struct packed_git *);\n-int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);\n+int verify_pack(struct repository *, struct packed_git *, verify_fn fn, void *fn_data,\n+\t\tstruct progress *, uint32_t);\n off_t write_pack_header(struct hashfile *f, uint32_t);\n void fixup_pack_header_footer(const struct git_hash_algo *, int,\n \t\t\t      unsigned char *, const char *, uint32_t,\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539745","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-11-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 11/12] builtin/fsck: stop using `the_repository` when marking objects","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:03:02Z","receivedAt":"2026-03-23T15:03:39Z","isPatch":true,"body":"We implicitly rely on `the_repository` when marking objects for\nconnectivity. Refactor this to instead inject the repository via the\ncallback payload.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 26 ++++++++++++++------------\n 1 file changed, 14 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 22ca1200a2..e37f708480 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -124,7 +124,7 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n static struct object_array pending;\n \n static int mark_object(struct object *obj, enum object_type type,\n-\t\t       void *data, struct fsck_options *options UNUSED)\n+\t\t       void *data, struct fsck_options *options)\n {\n \tstruct object *parent = data;\n \n@@ -153,7 +153,7 @@ static int mark_object(struct object *obj, enum object_type type,\n \t\treturn 0;\n \tobj->flags |= REACHABLE;\n \n-\tif (is_promisor_object(the_repository, &obj->oid))\n+\tif (is_promisor_object(options->repo, &obj->oid))\n \t\t/*\n \t\t * Further recursion does not need to be performed on this\n \t\t * object since it is a promisor object (so it does not need to\n@@ -162,7 +162,7 @@ static int mark_object(struct object *obj, enum object_type type,\n \t\treturn 0;\n \n \tif (!(obj->flags & HAS_OBJ)) {\n-\t\tif (parent && !odb_has_object(the_repository->objects, &obj->oid,\n+\t\tif (parent && !odb_has_object(options->repo->objects, &obj->oid,\n \t\t\t\t\t      HAS_OBJECT_RECHECK_PACKED)) {\n \t\t\tprintf_ln(_(\"broken link from %7s %s\\n\"\n \t\t\t\t    \"              to %7s %s\"),\n@@ -181,7 +181,7 @@ static int mark_object(struct object *obj, enum object_type type,\n \n static void mark_object_reachable(struct object *obj)\n {\n-\tmark_object(obj, OBJ_ANY, NULL, NULL);\n+\tmark_object(obj, OBJ_ANY, NULL, &fsck_walk_options);\n }\n \n static int traverse_one_object(struct object *obj)\n@@ -222,10 +222,11 @@ static int mark_used(struct object *obj, enum object_type type UNUSED,\n \n static int mark_unreachable_referents(const struct object_id *oid,\n \t\t\t\t      struct object_info *oi UNUSED,\n-\t\t\t\t      void *data UNUSED)\n+\t\t\t\t      void *data)\n {\n+\tstruct repository *repo = data;\n \tstruct fsck_options options;\n-\tstruct object *obj = lookup_object(the_repository, oid);\n+\tstruct object *obj = lookup_object(data, oid);\n \n \tif (!obj || !(obj->flags & HAS_OBJ))\n \t\treturn 0; /* not part of our original set */\n@@ -237,13 +238,13 @@ static int mark_unreachable_referents(const struct object_id *oid,\n \t * (and we want to avoid parsing blobs).\n \t */\n \tif (obj->type == OBJ_NONE) {\n-\t\tenum object_type type = odb_read_object_info(the_repository->objects,\n+\t\tenum object_type type = odb_read_object_info(repo->objects,\n \t\t\t\t\t\t\t     &obj->oid, NULL);\n \t\tif (type > 0)\n \t\t\tobject_as_type(obj, type, 0);\n \t}\n \n-\tfsck_options_init(&options, the_repository, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&options, repo, FSCK_OPTIONS_DEFAULT);\n \toptions.walk = mark_used;\n \tfsck_walk(obj, NULL, &options);\n \tif (obj->type == OBJ_TREE)\n@@ -385,7 +386,7 @@ static void check_connectivity(struct repository *repo)\n \t\t * traversal.\n \t\t */\n \t\todb_for_each_object(repo->objects, NULL,\n-\t\t\t\t    mark_unreachable_referents, NULL, 0);\n+\t\t\t\t    mark_unreachable_referents, repo, 0);\n \t}\n \n \t/* Look up all the requirements, warn about missing objects.. */\n@@ -909,9 +910,10 @@ static void fsck_index(struct index_state *istate, const char *index_path,\n \n static int mark_object_for_connectivity(const struct object_id *oid,\n \t\t\t\t\tstruct object_info *oi UNUSED,\n-\t\t\t\t\tvoid *cb_data UNUSED)\n+\t\t\t\t\tvoid *cb_data)\n {\n-\tstruct object *obj = lookup_unknown_object(the_repository, oid);\n+\tstruct repository *repo = cb_data;\n+\tstruct object *obj = lookup_unknown_object(repo, oid);\n \tobj->flags |= HAS_OBJ;\n \treturn 0;\n }\n@@ -1065,7 +1067,7 @@ int cmd_fsck(int argc,\n \n \tif (connectivity_only) {\n \t\todb_for_each_object(repo->objects, NULL,\n-\t\t\t\t    mark_object_for_connectivity, NULL, 0);\n+\t\t\t\t    mark_object_for_connectivity, repo, 0);\n \t} else {\n \t\todb_prepare_alternates(repo->objects);\n \t\tfor (source = repo->objects->sources; source; source = source->next)\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539746","messageId":"20260323-b4-pks-fsck-without-the-repository-v2-12-e8dc79bca651@pks.im","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"[PATCH v2 12/12] builtin/fsck: stop using `the_repository` in error reporting","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-23T15:03:03Z","receivedAt":"2026-03-23T15:03:41Z","isPatch":true,"body":"In the preceding commit we have introduced the repository into `struct\nfsck_object_report`. This allows us to drop remaining uses of the global\n`the_repository` variable.\n\nDrop them and remove `USE_THE_REPOSITORY_VARIABLE`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fsck.c | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex e37f708480..99696604b8 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -1,4 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n@@ -66,14 +65,14 @@ static const char *describe_object(const struct object_id *oid)\n \treturn fsck_describe_object(&fsck_walk_options, oid);\n }\n \n-static const char *printable_type(const struct object_id *oid,\n+static const char *printable_type(struct repository *repo,\n+\t\t\t\t  const struct object_id *oid,\n \t\t\t\t  enum object_type type)\n {\n \tconst char *ret;\n \n \tif (type == OBJ_NONE)\n-\t\ttype = odb_read_object_info(the_repository->objects,\n-\t\t\t\t\t    oid, NULL);\n+\t\ttype = odb_read_object_info(repo->objects, oid, NULL);\n \n \tret = type_name(type);\n \tif (!ret)\n@@ -82,17 +81,17 @@ static const char *printable_type(const struct object_id *oid,\n \treturn ret;\n }\n \n-static int objerror(struct object *obj, const char *err)\n+static int objerror(struct repository *repo, struct object *obj, const char *err)\n {\n \terrors_found |= ERROR_OBJECT;\n \t/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */\n \tfprintf_ln(stderr, _(\"error in %s %s: %s\"),\n-\t\t   printable_type(&obj->oid, obj->type),\n+\t\t   printable_type(repo, &obj->oid, obj->type),\n \t\t   describe_object(&obj->oid), err);\n \treturn -1;\n }\n \n-static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n+static int fsck_objects_error_func(struct fsck_options *o,\n \t\t\t\t   void *fsck_report,\n \t\t\t\t   enum fsck_msg_type msg_type,\n \t\t\t\t   enum fsck_msg_id msg_id UNUSED,\n@@ -106,13 +105,13 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,\n \tcase FSCK_WARN:\n \t\t/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */\n \t\tfprintf_ln(stderr, _(\"warning in %s %s: %s\"),\n-\t\t\t   printable_type(oid, object_type),\n+\t\t\t   printable_type(o->repo, oid, object_type),\n \t\t\t   describe_object(oid), message);\n \t\treturn 0;\n \tcase FSCK_ERROR:\n \t\t/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */\n \t\tfprintf_ln(stderr, _(\"error in %s %s: %s\"),\n-\t\t\t   printable_type(oid, object_type),\n+\t\t\t   printable_type(o->repo, oid, object_type),\n \t\t\t   describe_object(oid), message);\n \t\treturn 1;\n \tdefault:\n@@ -136,7 +135,7 @@ static int mark_object(struct object *obj, enum object_type type,\n \tif (!obj) {\n \t\t/* ... these references to parent->fld are safe here */\n \t\tprintf_ln(_(\"broken link from %7s %s\"),\n-\t\t\t  printable_type(&parent->oid, parent->type),\n+\t\t\t  printable_type(options->repo, &parent->oid, parent->type),\n \t\t\t  describe_object(&parent->oid));\n \t\tprintf_ln(_(\"broken link from %7s %s\"),\n \t\t\t  (type == OBJ_ANY ? _(\"unknown\") : type_name(type)),\n@@ -147,7 +146,7 @@ static int mark_object(struct object *obj, enum object_type type,\n \n \tif (type != OBJ_ANY && obj->type != type)\n \t\t/* ... and the reference to parent is safe here */\n-\t\tobjerror(parent, _(\"wrong object type in link\"));\n+\t\tobjerror(options->repo, parent, _(\"wrong object type in link\"));\n \n \tif (obj->flags & REACHABLE)\n \t\treturn 0;\n@@ -166,9 +165,9 @@ static int mark_object(struct object *obj, enum object_type type,\n \t\t\t\t\t      HAS_OBJECT_RECHECK_PACKED)) {\n \t\t\tprintf_ln(_(\"broken link from %7s %s\\n\"\n \t\t\t\t    \"              to %7s %s\"),\n-\t\t\t\t  printable_type(&parent->oid, parent->type),\n+\t\t\t\t  printable_type(options->repo, &parent->oid, parent->type),\n \t\t\t\t  describe_object(&parent->oid),\n-\t\t\t\t  printable_type(&obj->oid, obj->type),\n+\t\t\t\t  printable_type(options->repo, &obj->oid, obj->type),\n \t\t\t\t  describe_object(&obj->oid));\n \t\t\terrors_found |= ERROR_REACHABLE;\n \t\t}\n@@ -269,7 +268,7 @@ static void check_reachable_object(struct repository *repo, struct object *obj)\n \t\tif (has_object_pack(repo, &obj->oid))\n \t\t\treturn; /* it is in pack - forget about it */\n \t\tprintf_ln(_(\"missing %s %s\"),\n-\t\t\t  printable_type(&obj->oid, obj->type),\n+\t\t\t  printable_type(repo, &obj->oid, obj->type),\n \t\t\t  describe_object(&obj->oid));\n \t\terrors_found |= ERROR_REACHABLE;\n \t\treturn;\n@@ -296,7 +295,7 @@ static void check_unreachable_object(struct repository *repo, struct object *obj\n \t */\n \tif (show_unreachable) {\n \t\tprintf_ln(_(\"unreachable %s %s\"),\n-\t\t\t  printable_type(&obj->oid, obj->type),\n+\t\t\t  printable_type(repo, &obj->oid, obj->type),\n \t\t\t  describe_object(&obj->oid));\n \t\treturn;\n \t}\n@@ -316,7 +315,7 @@ static void check_unreachable_object(struct repository *repo, struct object *obj\n \tif (!(obj->flags & USED)) {\n \t\tif (show_dangling)\n \t\t\tprintf_ln(_(\"dangling %s %s\"),\n-\t\t\t\t  printable_type(&obj->oid, obj->type),\n+\t\t\t\t  printable_type(repo, &obj->oid, obj->type),\n \t\t\t\t  describe_object(&obj->oid));\n \t\tif (write_lost_and_found) {\n \t\t\tchar *filename = repo_git_path(repo, \"lost-found/%s/%s\",\n@@ -402,7 +401,8 @@ static void check_connectivity(struct repository *repo)\n \t}\n }\n \n-static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n+static int fsck_obj(struct repository *repo,\n+\t\t    struct object *obj, void *buffer, unsigned long size)\n {\n \tint err;\n \n@@ -412,11 +412,11 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n \n \tif (verbose)\n \t\tfprintf_ln(stderr, _(\"Checking %s %s\"),\n-\t\t\t   printable_type(&obj->oid, obj->type),\n+\t\t\t   printable_type(repo, &obj->oid, obj->type),\n \t\t\t   describe_object(&obj->oid));\n \n \tif (fsck_walk(obj, NULL, &fsck_obj_options))\n-\t\tobjerror(obj, _(\"broken links\"));\n+\t\tobjerror(repo, obj, _(\"broken links\"));\n \terr = fsck_object(obj, buffer, size, &fsck_obj_options);\n \tif (err)\n \t\tgoto out;\n@@ -434,7 +434,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)\n \n \t\tif (show_tags && tag->tagged) {\n \t\t\tprintf_ln(_(\"tagged %s %s (%s) in %s\"),\n-\t\t\t\t  printable_type(&tag->tagged->oid, tag->tagged->type),\n+\t\t\t\t  printable_type(repo, &tag->tagged->oid, tag->tagged->type),\n \t\t\t\t  describe_object(&tag->tagged->oid),\n \t\t\t\t  tag->tag,\n \t\t\t\t  describe_object(&tag->object.oid));\n@@ -465,7 +465,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,\n \t}\n \tobj->flags &= ~(REACHABLE | SEEN);\n \tobj->flags |= HAS_OBJ;\n-\treturn fsck_obj(obj, buffer, size);\n+\treturn fsck_obj(repo, obj, buffer, size);\n }\n \n static int default_refs;\n@@ -765,7 +765,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,\n \n \tobj->flags &= ~(REACHABLE | SEEN);\n \tobj->flags |= HAS_OBJ;\n-\tif (fsck_obj(obj, contents, size))\n+\tif (fsck_obj(data->repo, obj, contents, size))\n \t\terrors_found |= ERROR_OBJECT;\n \n \tif (!eaten)\n@@ -830,7 +830,7 @@ static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const\n \t\tfsck_put_object_name(&fsck_walk_options, &it->oid, \":\");\n \t\tmark_object_reachable(obj);\n \t\tif (obj->type != OBJ_TREE)\n-\t\t\terr |= objerror(obj, _(\"non-tree in cache-tree\"));\n+\t\t\terr |= objerror(repo, obj, _(\"non-tree in cache-tree\"));\n \t}\n \tfor (i = 0; i < it->subtree_nr; i++)\n \t\terr |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path);\n\n-- \n2.53.0.1118.gaef5881109.dirty\n\n"},{"id":"539750","messageId":"xmqqv7em5z60.fsf@gitster.g","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-1-e8dc79bca651@pks.im","subject":"Re: [PATCH v2 01/12] fetch-pack: move fsck options into function scope","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-23T15:43:51Z","receivedAt":"2026-03-23T15:43:53Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> When fetching a packfile, we optionally verify received objects via the\n> fsck subsystem. The options for those consistency checks are declared in\n> global scope without a good reason, and they are never cleaned up. So in\n> case the options are reused, they may accumulate more state over time.\n\nGreat realization.\n\nSo we have two code paths (the original and v2), both of which used\nto use the one in the global scope without cleaning up, but now we\nhave a way to proerly clean them up.  Very nice.\n\n> Furthermore, in subsequent changes we'll introduce a repository pointer\n> into the structure. Obviously though, we don't have a repository\n> available at static time, except for `the_repository`, which we don't\n> want to use here.\n>\n> Refactor the code to move the options into the respective functions and\n> properly manage their lifecycle.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  fetch-pack.c | 5 ++++-\n>  1 file changed, 4 insertions(+), 1 deletion(-)\n>\n> diff --git a/fetch-pack.c b/fetch-pack.c\n> index 6ecd468ef7..ec5abb92b5 100644\n> --- a/fetch-pack.c\n> +++ b/fetch-pack.c\n> @@ -51,7 +51,6 @@ static int server_supports_filtering;\n>  static int advertise_sid;\n>  static struct shallow_lock shallow_lock;\n>  static const char *alternate_shallow_file;\n> -static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n>  static struct strbuf fsck_msg_types = STRBUF_INIT;\n>  static struct string_list uri_protocols = STRING_LIST_INIT_DUP;\n>  \n> @@ -1100,6 +1099,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n>  \t\t\t\t struct shallow_info *si,\n>  \t\t\t\t struct string_list *pack_lockfiles)\n>  {\n> +\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n>  \tstruct repository *r = the_repository;\n>  \tstruct ref *ref = copy_ref_list(orig_ref);\n>  \tstruct object_id oid;\n> @@ -1235,6 +1235,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n>  \t\tdie(\"fsck failed\");\n>  \n>   all_done:\n> +\tfsck_options_clear(&fsck_options);\n>  \tif (negotiator)\n>  \t\tnegotiator->release(negotiator);\n>  \treturn ref;\n> @@ -1654,6 +1655,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n>  \t\t\t\t    struct string_list *pack_lockfiles)\n>  {\n>  \tstruct repository *r = the_repository;\n> +\tstruct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;\n>  \tstruct ref *ref = copy_ref_list(orig_ref);\n>  \tenum fetch_state state = FETCH_CHECK_LOCAL;\n>  \tstruct oidset common = OIDSET_INIT;\n> @@ -1882,6 +1884,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,\n>  \tif (negotiator)\n>  \t\tnegotiator->release(negotiator);\n>  \n> +\tfsck_options_clear(&fsck_options);\n>  \toidset_clear(&common);\n>  \treturn ref;\n>  }\n"},{"id":"539751","messageId":"xmqqqzpa5yyo.fsf@gitster.g","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-2-e8dc79bca651@pks.im","subject":"Re: [PATCH v2 02/12] fsck: initialize fsck options via a function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-23T15:48:15Z","receivedAt":"2026-03-23T15:48:18Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> +void fsck_options_init(struct fsck_options *options,\n> +\t\t       enum fsck_options_type type)\n> +{\n> +\tstatic const struct fsck_options defaults[] = {\n> +\t\t[FSCK_OPTIONS_DEFAULT] = {\n> +\t\t\t.skip_oids = OIDSET_INIT,\n> +\t\t\t.gitmodules_found = OIDSET_INIT,\n> +\t\t\t.gitmodules_done = OIDSET_INIT,\n> +\t\t\t.gitattributes_found = OIDSET_INIT,\n> +\t\t\t.gitattributes_done = OIDSET_INIT,\n> +\t\t\t.error_func = fsck_objects_error_function\n> +\t\t},\n> +\t\t[FSCK_OPTIONS_STRICT] = {\n> +\t\t\t.strict = 1,\n> +\t\t\t.gitmodules_found = OIDSET_INIT,\n> +\t\t\t.gitmodules_done = OIDSET_INIT,\n> +\t\t\t.gitattributes_found = OIDSET_INIT,\n> +\t\t\t.gitattributes_done = OIDSET_INIT,\n> +\t\t\t.error_func = fsck_objects_error_function,\n> +\t\t},\n> +\t\t[FSCK_OPTIONS_MISSING_GITMODULES] = {\n> +\t\t\t.strict = 1,\n> +\t\t\t.gitmodules_found = OIDSET_INIT,\n> +\t\t\t.gitmodules_done = OIDSET_INIT,\n> +\t\t\t.gitattributes_found = OIDSET_INIT,\n> +\t\t\t.gitattributes_done = OIDSET_INIT,\n> +\t\t\t.error_func = fsck_objects_error_cb_print_missing_gitmodules,\n> +\t\t},\n> +\t\t[FSCK_OPTIONS_REFS] = {\n> +\t\t\t.error_func = fsck_refs_error_function,\n> +\t\t},\n> +\t};\n> +\n> +\tswitch (type) {\n> +\tcase FSCK_OPTIONS_DEFAULT:\n> +\tcase FSCK_OPTIONS_STRICT:\n> +\tcase FSCK_OPTIONS_MISSING_GITMODULES:\n> +\tcase FSCK_OPTIONS_REFS:\n> +\t\tmemcpy(options, &defaults[type], sizeof(*options));\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"unknown fsck options type %d\", type);\n> +\t}\n> +}\n\nWow, nice reorganization that migrates the earlier definitions from\nthe header file.\n\nBy reusing these FSCK_OPTIONS_* names as an enum elements, we will\nlet the compiler catch if any other branch adds new uses of these\nnames with their original meaning, which is a nice touch, too.\n\n>  void fsck_options_clear(struct fsck_options *options)\n>  {\n>  \tfree(options->msg_type);\n> diff --git a/fsck.h b/fsck.h\n> index 65ecbb7fe1..9c973b53b2 100644\n> --- a/fsck.h\n> +++ b/fsck.h\n> @@ -180,34 +180,6 @@ struct fsck_options {\n>  \tkh_oid_map_t *object_names;\n>  };\n>  \n> -#define FSCK_OPTIONS_DEFAULT { \\\n> -\t.skip_oids = OIDSET_INIT, \\\n> -\t.gitmodules_found = OIDSET_INIT, \\\n> -\t.gitmodules_done = OIDSET_INIT, \\\n> -\t.gitattributes_found = OIDSET_INIT, \\\n> -\t.gitattributes_done = OIDSET_INIT, \\\n> -\t.error_func = fsck_objects_error_function \\\n> -}\n> -#define FSCK_OPTIONS_STRICT { \\\n> -\t.strict = 1, \\\n> -\t.gitmodules_found = OIDSET_INIT, \\\n> -\t.gitmodules_done = OIDSET_INIT, \\\n> -\t.gitattributes_found = OIDSET_INIT, \\\n> -\t.gitattributes_done = OIDSET_INIT, \\\n> -\t.error_func = fsck_objects_error_function, \\\n> -}\n> -#define FSCK_OPTIONS_MISSING_GITMODULES { \\\n> -\t.strict = 1, \\\n> -\t.gitmodules_found = OIDSET_INIT, \\\n> -\t.gitmodules_done = OIDSET_INIT, \\\n> -\t.gitattributes_found = OIDSET_INIT, \\\n> -\t.gitattributes_done = OIDSET_INIT, \\\n> -\t.error_func = fsck_objects_error_cb_print_missing_gitmodules, \\\n> -}\n> -#define FSCK_REFS_OPTIONS_DEFAULT { \\\n> -\t.error_func = fsck_refs_error_function, \\\n> -}\n> -\n>  /* descend in all linked child objects\n>   * the return value is:\n>   *    -1\terror in processing the object\n> @@ -255,6 +227,16 @@ int fsck_finish(struct fsck_options *options);\n>   */\n>  bool fsck_has_queued_checks(struct fsck_options *options);\n>  \n> +enum fsck_options_type {\n> +\tFSCK_OPTIONS_DEFAULT,\n> +\tFSCK_OPTIONS_STRICT,\n> +\tFSCK_OPTIONS_MISSING_GITMODULES,\n> +\tFSCK_OPTIONS_REFS,\n> +};\n> +\n> +void fsck_options_init(struct fsck_options *options,\n> +\t\t       enum fsck_options_type type);\n> +\n>  /*\n>   * Clear the fsck_options struct, freeing any allocated memory.\n>   */\n> diff --git a/object-file.c b/object-file.c\n> index c62e5496e0..186b2ff764 100644\n> --- a/object-file.c\n> +++ b/object-file.c\n> @@ -1279,8 +1279,9 @@ static int index_mem(struct index_state *istate,\n>  \t\t}\n>  \t}\n>  \tif (flags & INDEX_FORMAT_CHECK) {\n> -\t\tstruct fsck_options opts = FSCK_OPTIONS_DEFAULT;\n> +\t\tstruct fsck_options opts;\n>  \n> +\t\tfsck_options_init(&opts, FSCK_OPTIONS_DEFAULT);\n>  \t\topts.strict = 1;\n>  \t\topts.error_func = hash_format_check_report;\n>  \t\tif (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))\n"},{"id":"540570","messageId":"xmqqy0j7wt7z.fsf@gitster.g","threadId":"65337","inReplyTo":"20260323-b4-pks-fsck-without-the-repository-v2-0-e8dc79bca651@pks.im","subject":"Re: [PATCH v2 00/12] fsck: drop use of `the_repository`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-03-31T22:05:04Z","receivedAt":"2026-03-31T22:05:07Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> this patch series refactors \"{builtin/,}fsck.c\" to not depend on\n> `the_repository` anymore. These refactorings are mostly done to prepare\n> for upcoming changes where we'll make backend-specific fsck checks\n> pluggable.\n>\n> Changes in v2:\n>   - Propagate the repository via `struct fsck_options`.\n>   - Link to v1: https://lore.kernel.org/r/20260320-b4-pks-fsck-without-the-repository-v1-0-6594f997926b@pks.im\n\nLooking good.  Shall we mark the topic for 'next' now?\n\nThanks.\n"},{"id":"540578","messageId":"acxPvS984rAPJxdl@pks.im","threadId":"65337","inReplyTo":"xmqqy0j7wt7z.fsf@gitster.g","subject":"Re: [PATCH v2 00/12] fsck: drop use of `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-03-31T22:50:37Z","receivedAt":"2026-03-31T22:50:43Z","isPatch":true,"body":"On Tue, Mar 31, 2026 at 03:05:04PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > this patch series refactors \"{builtin/,}fsck.c\" to not depend on\n> > `the_repository` anymore. These refactorings are mostly done to prepare\n> > for upcoming changes where we'll make backend-specific fsck checks\n> > pluggable.\n> >\n> > Changes in v2:\n> >   - Propagate the repository via `struct fsck_options`.\n> >   - Link to v1: https://lore.kernel.org/r/20260320-b4-pks-fsck-without-the-repository-v1-0-6594f997926b@pks.im\n> \n> Looking good.  Shall we mark the topic for 'next' now?\n\nNo more changes are planned on my side, so I'm fine with that. Thanks!\n\nPatrick\n"}]}