{"thread":{"id":"61496","subject":"[PATCH v2 00/16] refs: drop all references to `the_repository`","startedAt":"2024-05-17T08:18:17Z","lastAt":"2024-05-17T08:19:34Z","messageCount":17,"participants":["Patrick Steinhardt"],"isPatch":true,"patchVersion":2,"patchTotal":16},"messages":[{"id":"494940","messageId":"cover.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":null,"subject":"[PATCH v2 00/16] refs: drop all references to `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:10Z","receivedAt":"2024-05-17T08:18:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis is the second version of my patch series that removes all\nreferences to `the_repository` and `the_hash_algo` in the refs\ninterfaces.\n\nChanges compared to v1:\n\n  - Fix duplicate word in commit message.\n\n  - Rename `ref_store_create()` to `ref_store_create_on_disk()`.\n\n  - Add a trace when calling `debug_release()`.\n\n  - Add a note in patch 5 that the newly added reference to\n    `the_repository` in `resolved_gitlink_ref()` gets fixed in the\n    following patch.\n\n  - Fix unsetting the worktree stack in `reftable_be_release()`.\n\nThanks!\n\nPatrick\n\nPatrick Steinhardt (16):\n  refs: adjust names for `init` and `init_db` callbacks\n  refs: rename `init_db` callback to avoid confusion\n  refs: implement releasing ref storages\n  refs: track ref stores via strmap\n  refs: pass repo when retrieving submodule ref store\n  refs: refactor `resolve_gitlink_ref()` to accept a repository\n  refs: retrieve worktree ref stores via associated repository\n  refs: convert iteration over replace refs to accept ref store\n  refs: pass ref store when detecting dangling symrefs\n  refs: move object peeling into \"object.c\"\n  refs: pass repo when peeling objects\n  refs: drop `git_default_branch_name()`\n  refs: remove `dwim_log()`\n  refs/files: use correct repository\n  refs/files: remove references to `the_hash_algo`\n  refs/packed: remove references to `the_hash_algo`\n\n attr.c                      |   3 +-\n builtin/clone.c             |   5 +-\n builtin/describe.c          |   2 +-\n builtin/fetch.c             |   3 +-\n builtin/gc.c                |   2 +-\n builtin/pack-objects.c      |   6 +-\n builtin/reflog.c            |   2 +-\n builtin/remote.c            |   3 +-\n builtin/repack.c            |   2 +-\n builtin/replace.c           |  13 +-\n builtin/show-ref.c          |   2 +-\n builtin/submodule--helper.c |  14 +-\n builtin/update-index.c      |   5 +-\n builtin/var.c               |   2 +-\n builtin/worktree.c          |   2 +-\n combine-diff.c              |   3 +-\n commit-graph.c              |   2 +-\n diff-lib.c                  |   3 +-\n dir.c                       |   3 +-\n ls-refs.c                   |   2 +-\n midx-write.c                |   2 +-\n object-file.c               |   2 +-\n object.c                    |  23 ++++\n object.h                    |  35 +++++\n read-cache.c                |   5 +-\n ref-filter.c                |   2 +-\n reflog-walk.c               |   4 +-\n reflog.c                    |   2 +-\n refs.c                      | 266 ++++++++++--------------------------\n refs.h                      |  51 +++----\n refs/debug.c                |  16 ++-\n refs/files-backend.c        |  59 ++++----\n refs/iterator.c             |   6 +-\n refs/packed-backend.c       |  67 +++++----\n refs/packed-backend.h       |   6 +-\n refs/ref-cache.c            |   5 +-\n refs/refs-internal.h        |  54 ++------\n refs/reftable-backend.c     |  39 +++++-\n remote.c                    |  12 +-\n replace-object.c            |  10 +-\n repository.c                |  12 ++\n repository.h                |  14 ++\n setup.c                     |   7 +-\n submodule.c                 |   3 +-\n t/helper/test-reach.c       |   2 +-\n t/helper/test-ref-store.c   |   2 +-\n tag.c                       |   4 +-\n tag.h                       |   2 +-\n unpack-trees.c              |   3 +-\n upload-pack.c               |   2 +-\n worktree.c                  |   2 +\n worktree.h                  |   2 +\n 52 files changed, 408 insertions(+), 392 deletions(-)\n\nRange-diff against v1:\n 1:  360d034746 !  1:  4225a6928a refs: adjust names for `init` and `init_db` callbacks\n    @@ Metadata\n      ## Commit message ##\n         refs: adjust names for `init` and `init_db` callbacks\n     \n    -    The names of the functions that implement the the `init` and `init_db`\n    +    The names of the functions that implement the `init` and `init_db`\n         callbacks in the \"files\" and \"packed\" backends do not match the names of\n         the callbacks, which is inconsistent. Rename them so that they match,\n         which makes it easier to discover their respective implementations.\n 2:  3cc2b4e550 !  2:  050fb24e58 refs: rename `init_db` callback to avoid confusion\n    @@ Commit message\n         refs: rename `init_db` callback to avoid confusion\n     \n         Reference backends have two callbacks `init` and `init_db`. The\n    -    similarity of these two callbacks has repeatedly tripped myself whenever\n    -    I was looking at those, where I always had to look up which of them does\n    +    similarity of these two callbacks has repeatedly confused me whenever I\n    +    was looking at them, where I always had to look up which of them does\n         what.\n     \n    -    Rename the `init_db` callback to `create`, which should hopefully be\n    -    clearer.\n    +    Rename the `init_db` callback to `create_on_disk`, which should\n    +    hopefully be clearer.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n    @@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam\n      \twt_refs = get_worktree_ref_store(wt);\n      \n     -\tret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);\n    -+\tret = ref_store_create(wt_refs, REF_STORE_CREATE_IS_WORKTREE, &sb);\n    ++\tret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);\n      \tif (ret)\n      \t\tgoto done;\n      \n    @@ refs.c: const char *refs_resolve_ref_unsafe(struct ref_store *refs,\n      \n      /* backend functions */\n     -int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n    -+int ref_store_create(struct ref_store *refs, int flags, struct strbuf *err)\n    ++int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n      {\n     -\treturn refs->be->init_db(refs, flags, err);\n    -+\treturn refs->be->create(refs, flags, err);\n    ++\treturn refs->be->create_on_disk(refs, flags, err);\n      }\n      \n      int resolve_gitlink_ref(const char *submodule, const char *refname,\n    @@ refs.h: int should_autocreate_reflog(const char *refname);\n      int is_branch(const char *refname);\n      \n     -#define REFS_INIT_DB_IS_WORKTREE (1 << 0)\n    -+#define REF_STORE_CREATE_IS_WORKTREE (1 << 0)\n    ++#define REF_STORE_CREATE_ON_DISK_IS_WORKTREE (1 << 0)\n      \n     -int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);\n    -+int ref_store_create(struct ref_store *refs, int flags, struct strbuf *err);\n    ++int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);\n      \n      /*\n       * Return the peeled value of the oid currently being iterated via\n    @@ refs/debug.c: struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, s\n      }\n      \n     -static int debug_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n    -+static int debug_create(struct ref_store *refs, int flags, struct strbuf *err)\n    ++static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n      {\n      \tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n     -\tint res = drefs->refs->be->init_db(drefs->refs, flags, err);\n     -\ttrace_printf_key(&trace_refs, \"init_db: %d\\n\", res);\n    -+\tint res = drefs->refs->be->create(drefs->refs, flags, err);\n    -+\ttrace_printf_key(&trace_refs, \"create: %d\\n\", res);\n    ++\tint res = drefs->refs->be->create_on_disk(drefs->refs, flags, err);\n    ++\ttrace_printf_key(&trace_refs, \"create_on_disk: %d\\n\", res);\n      \treturn res;\n      }\n      \n    @@ refs/debug.c: static int debug_reflog_expire(struct ref_store *ref_store, const\n      \t.name = \"debug\",\n      \t.init = NULL,\n     -\t.init_db = debug_init_db,\n    -+\t.create = debug_create,\n    ++\t.create_on_disk = debug_create_on_disk,\n      \n      \t/*\n      \t * None of these should be NULL. If the \"files\" backend (in\n    @@ refs/files-backend.c: static int files_reflog_expire(struct ref_store *ref_store\n     -static int files_init_db(struct ref_store *ref_store,\n     -\t\t\t int flags,\n     -\t\t\t struct strbuf *err UNUSED)\n    -+static int files_ref_store_create(struct ref_store *ref_store,\n    -+\t\t\t\t  int flags,\n    -+\t\t\t\t  struct strbuf *err UNUSED)\n    ++static int files_ref_store_create_on_disk(struct ref_store *ref_store,\n    ++\t\t\t\t\t  int flags,\n    ++\t\t\t\t\t  struct strbuf *err UNUSED)\n      {\n      \tstruct files_ref_store *refs =\n     -\t\tfiles_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n    @@ refs/files-backend.c: static int files_init_db(struct ref_store *ref_store,\n      \t * a worktree ref store.\n      \t */\n     -\tif (!(flags & REFS_INIT_DB_IS_WORKTREE)) {\n    -+\tif (!(flags & REF_STORE_CREATE_IS_WORKTREE)) {\n    ++\tif (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {\n      \t\t/*\n      \t\t * Create .git/refs/{heads,tags}\n      \t\t */\n    @@ refs/files-backend.c: static int files_init_db(struct ref_store *ref_store,\n      \t.name = \"files\",\n      \t.init = files_ref_store_init,\n     -\t.init_db = files_init_db,\n    -+\t.create = files_ref_store_create,\n    ++\t.create_on_disk = files_ref_store_create_on_disk,\n      \t.transaction_prepare = files_transaction_prepare,\n      \t.transaction_finish = files_transaction_finish,\n      \t.transaction_abort = files_transaction_abort,\n    @@ refs/packed-backend.c: int packed_refs_is_locked(struct ref_store *ref_store)\n     -static int packed_ref_store_init_db(struct ref_store *ref_store UNUSED,\n     -\t\t\t\t    int flags UNUSED,\n     -\t\t\t\t    struct strbuf *err UNUSED)\n    -+static int packed_ref_store_create(struct ref_store *ref_store UNUSED,\n    -+\t\t\t\t   int flags UNUSED,\n    -+\t\t\t\t   struct strbuf *err UNUSED)\n    ++static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,\n    ++\t\t\t\t\t   int flags UNUSED,\n    ++\t\t\t\t\t   struct strbuf *err UNUSED)\n      {\n      \t/* Nothing to do. */\n      \treturn 0;\n    @@ refs/packed-backend.c: static struct ref_iterator *packed_reflog_iterator_begin(\n      \t.name = \"packed\",\n      \t.init = packed_ref_store_init,\n     -\t.init_db = packed_ref_store_init_db,\n    -+\t.create = packed_ref_store_create,\n    ++\t.create_on_disk = packed_ref_store_create_on_disk,\n      \t.transaction_prepare = packed_transaction_prepare,\n      \t.transaction_finish = packed_transaction_finish,\n      \t.transaction_abort = packed_transaction_abort,\n    @@ refs/refs-internal.h: typedef struct ref_store *ref_store_init_fn(struct reposit\n     -typedef int ref_init_db_fn(struct ref_store *refs,\n     -\t\t\t   int flags,\n     -\t\t\t   struct strbuf *err);\n    -+typedef int ref_store_create_fn(struct ref_store *refs,\n    -+\t\t\t\tint flags,\n    -+\t\t\t\tstruct strbuf *err);\n    ++typedef int ref_store_create_on_disk_fn(struct ref_store *refs,\n    ++\t\t\t\t\tint flags,\n    ++\t\t\t\t\tstruct strbuf *err);\n      \n      typedef int ref_transaction_prepare_fn(struct ref_store *refs,\n      \t\t\t\t       struct ref_transaction *transaction,\n    @@ refs/refs-internal.h: typedef int read_symbolic_ref_fn(struct ref_store *ref_sto\n      \tconst char *name;\n      \tref_store_init_fn *init;\n     -\tref_init_db_fn *init_db;\n    -+\tref_store_create_fn *create;\n    ++\tref_store_create_on_disk_fn *create_on_disk;\n      \n      \tref_transaction_prepare_fn *transaction_prepare;\n      \tref_transaction_finish_fn *transaction_finish;\n    @@ refs/reftable-backend.c: static struct ref_store *reftable_be_init(struct reposi\n     -static int reftable_be_init_db(struct ref_store *ref_store,\n     -\t\t\t       int flags UNUSED,\n     -\t\t\t       struct strbuf *err UNUSED)\n    -+static int reftable_be_create(struct ref_store *ref_store,\n    -+\t\t\t      int flags UNUSED,\n    -+\t\t\t      struct strbuf *err UNUSED)\n    ++static int reftable_be_create_on_disk(struct ref_store *ref_store,\n    ++\t\t\t\t      int flags UNUSED,\n    ++\t\t\t\t      struct strbuf *err UNUSED)\n      {\n      \tstruct reftable_ref_store *refs =\n     -\t\treftable_be_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n    @@ refs/reftable-backend.c: static int reftable_be_reflog_expire(struct ref_store *\n      \t.name = \"reftable\",\n      \t.init = reftable_be_init,\n     -\t.init_db = reftable_be_init_db,\n    -+\t.create = reftable_be_create,\n    ++\t.create_on_disk = reftable_be_create_on_disk,\n      \t.transaction_prepare = reftable_be_transaction_prepare,\n      \t.transaction_finish = reftable_be_transaction_finish,\n      \t.transaction_abort = reftable_be_transaction_abort,\n    @@ setup.c: void create_reference_database(unsigned int ref_storage_format,\n      \n      \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n     -\tif (refs_init_db(get_main_ref_store(the_repository), 0, &err))\n    -+\tif (ref_store_create(get_main_ref_store(the_repository), 0, &err))\n    ++\tif (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &err))\n      \t\tdie(\"failed to set up refs db: %s\", err.buf);\n      \n      \t/*\n 3:  282fbe35a7 !  3:  4beecb0944 refs: implement releasing ref storages\n    @@ refs.c: static struct ref_store *ref_store_init(struct repository *repo,\n      ## refs.h ##\n     @@ refs.h: int is_branch(const char *refname);\n      \n    - int ref_store_create(struct ref_store *refs, int flags, struct strbuf *err);\n    + int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);\n      \n     +/*\n     + * Release all memory and resources associated with the ref store.\n    @@ refs/debug.c: struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, s\n     +{\n     +\tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n     +\tdrefs->refs->be->release(drefs->refs);\n    ++\ttrace_printf_key(&trace_refs, \"release\\n\");\n     +}\n     +\n    - static int debug_create(struct ref_store *refs, int flags, struct strbuf *err)\n    + static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n      {\n      \tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n     @@ refs/debug.c: static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,\n    @@ refs/debug.c: static int debug_reflog_expire(struct ref_store *ref_store, const\n      \t.name = \"debug\",\n      \t.init = NULL,\n     +\t.release = debug_release,\n    - \t.create = debug_create,\n    + \t.create_on_disk = debug_create_on_disk,\n      \n      \t/*\n     \n    @@ refs/files-backend.c: static struct files_ref_store *files_downcast(struct ref_s\n      static void files_reflog_path(struct files_ref_store *refs,\n      \t\t\t      struct strbuf *sb,\n      \t\t\t      const char *refname)\n    -@@ refs/files-backend.c: static int files_ref_store_create(struct ref_store *ref_store,\n    +@@ refs/files-backend.c: static int files_ref_store_create_on_disk(struct ref_store *ref_store,\n      struct ref_storage_be refs_be_files = {\n      \t.name = \"files\",\n      \t.init = files_ref_store_init,\n     +\t.release = files_ref_store_release,\n    - \t.create = files_ref_store_create,\n    + \t.create_on_disk = files_ref_store_create_on_disk,\n    ++\n      \t.transaction_prepare = files_transaction_prepare,\n      \t.transaction_finish = files_transaction_finish,\n    + \t.transaction_abort = files_transaction_abort,\n     \n      ## refs/packed-backend.c ##\n     @@ refs/packed-backend.c: static void clear_snapshot(struct packed_ref_store *refs)\n    @@ refs/packed-backend.c: static struct ref_iterator *packed_reflog_iterator_begin(\n      \t.name = \"packed\",\n      \t.init = packed_ref_store_init,\n     +\t.release = packed_ref_store_release,\n    - \t.create = packed_ref_store_create,\n    + \t.create_on_disk = packed_ref_store_create_on_disk,\n    ++\n      \t.transaction_prepare = packed_transaction_prepare,\n      \t.transaction_finish = packed_transaction_finish,\n    + \t.transaction_abort = packed_transaction_abort,\n     \n      ## refs/refs-internal.h ##\n    -@@ refs/refs-internal.h: typedef struct ref_store *ref_store_init_fn(struct repository *repo,\n    +@@ refs/refs-internal.h: struct ref_store;\n    + typedef struct ref_store *ref_store_init_fn(struct repository *repo,\n      \t\t\t\t\t    const char *gitdir,\n      \t\t\t\t\t    unsigned int flags);\n    - \n     +/*\n     + * Release all memory and resources associated with the ref store.\n     + */\n     +typedef void ref_store_release_fn(struct ref_store *refs);\n    -+\n    - typedef int ref_store_create_fn(struct ref_store *refs,\n    - \t\t\t\tint flags,\n    - \t\t\t\tstruct strbuf *err);\n    + \n    + typedef int ref_store_create_on_disk_fn(struct ref_store *refs,\n    + \t\t\t\t\tint flags,\n     @@ refs/refs-internal.h: typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam\n      struct ref_storage_be {\n      \tconst char *name;\n      \tref_store_init_fn *init;\n     +\tref_store_release_fn *release;\n    - \tref_store_create_fn *create;\n    + \tref_store_create_on_disk_fn *create_on_disk;\n      \n      \tref_transaction_prepare_fn *transaction_prepare;\n     \n    @@ refs/reftable-backend.c: static struct ref_store *reftable_be_init(struct reposi\n     +\n     +\tif (refs->worktree_stack) {\n     +\t\treftable_stack_destroy(refs->worktree_stack);\n    -+\t\trefs->main_stack = NULL;\n    ++\t\trefs->worktree_stack = NULL;\n     +\t}\n     +\n     +\tstrmap_for_each_entry(&refs->worktree_stacks, &iter, entry)\n    @@ refs/reftable-backend.c: static struct ref_store *reftable_be_init(struct reposi\n     +\tstrmap_clear(&refs->worktree_stacks, 0);\n     +}\n     +\n    - static int reftable_be_create(struct ref_store *ref_store,\n    - \t\t\t      int flags UNUSED,\n    - \t\t\t      struct strbuf *err UNUSED)\n    + static int reftable_be_create_on_disk(struct ref_store *ref_store,\n    + \t\t\t\t      int flags UNUSED,\n    + \t\t\t\t      struct strbuf *err UNUSED)\n     @@ refs/reftable-backend.c: static int reftable_be_reflog_expire(struct ref_store *ref_store,\n      struct ref_storage_be refs_be_reftable = {\n      \t.name = \"reftable\",\n      \t.init = reftable_be_init,\n     +\t.release = reftable_be_release,\n    - \t.create = reftable_be_create,\n    + \t.create_on_disk = reftable_be_create_on_disk,\n    ++\n      \t.transaction_prepare = reftable_be_transaction_prepare,\n      \t.transaction_finish = reftable_be_transaction_finish,\n    + \t.transaction_abort = reftable_be_transaction_abort,\n 4:  52798936a2 =  4:  9ca54a12e8 refs: track ref stores via strmap\n 5:  1d48289809 !  5:  d7f8b2f40d refs: pass repo when retrieving submodule ref store\n    @@ Commit message\n         move the global map into `struct repository`. Like this it becomes\n         possible to look up submodule ref stores for arbitrary repositories.\n     \n    +    Note that this also adds a new reference to `the_repository` in\n    +    `resolve_gitlink_ref()`, which is part of the refs interfaces. This will\n    +    get adjusted in the next patch.\n    +\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## builtin/submodule--helper.c ##\n 6:  7b4ea1ffd2 !  6:  a8593b16a6 refs: refactor `resolve_gitlink_ref()` to accept a repository\n    @@ read-cache.c: int add_to_index(struct index_state *istate, const char *path, str\n      \t\t\tnamelen--;\n     \n      ## refs.c ##\n    -@@ refs.c: int ref_store_create(struct ref_store *refs, int flags, struct strbuf *err)\n    - \treturn refs->be->create(refs, flags, err);\n    +@@ refs.c: int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e\n    + \treturn refs->be->create_on_disk(refs, flags, err);\n      }\n      \n     -int resolve_gitlink_ref(const char *submodule, const char *refname,\n 7:  4d55dbbceb =  7:  977f3a8510 refs: retrieve worktree ref stores via associated repository\n 8:  160e64e42a =  8:  5306122d58 refs: convert iteration over replace refs to accept ref store\n 9:  50c5d72c6a =  9:  423d7b3fb6 refs: pass ref store when detecting dangling symrefs\n10:  f03626ac00 = 10:  3c6f814158 refs: move object peeling into \"object.c\"\n11:  eb60ce5771 = 11:  272cd49357 refs: pass repo when peeling objects\n12:  09ca848e7d = 12:  e02e76701f refs: drop `git_default_branch_name()`\n13:  da10714a45 = 13:  afa9184884 refs: remove `dwim_log()`\n14:  7ce6b7454d = 14:  c1a2dc4e69 refs/files: use correct repository\n15:  ab0c793739 = 15:  20c2bb4cbb refs/files: remove references to `the_hash_algo`\n16:  9cd554166f = 16:  5ebe81d8c3 refs/packed: remove references to `the_hash_algo`\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494941","messageId":"4225a6928ab5119d8d6844c6a7a13f1975137767.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 01/16] refs: adjust names for `init` and `init_db` callbacks","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:14Z","receivedAt":"2024-05-17T08:18:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The names of the functions that implement the `init` and `init_db`\ncallbacks in the \"files\" and \"packed\" backends do not match the names of\nthe callbacks, which is inconsistent. Rename them so that they match,\nwhich makes it easier to discover their respective implementations.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/files-backend.c  | 10 +++++-----\n refs/packed-backend.c | 16 ++++++++--------\n refs/packed-backend.h |  6 +++---\n 3 files changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex a098d14ea0..2c9d5e0747 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -89,9 +89,9 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)\n  * Create a new submodule ref cache and add it to the internal\n  * set of caches.\n  */\n-static struct ref_store *files_ref_store_create(struct repository *repo,\n-\t\t\t\t\t\tconst char *gitdir,\n-\t\t\t\t\t\tunsigned int flags)\n+static struct ref_store *files_ref_store_init(struct repository *repo,\n+\t\t\t\t\t      const char *gitdir,\n+\t\t\t\t\t      unsigned int flags)\n {\n \tstruct files_ref_store *refs = xcalloc(1, sizeof(*refs));\n \tstruct ref_store *ref_store = (struct ref_store *)refs;\n@@ -102,7 +102,7 @@ static struct ref_store *files_ref_store_create(struct repository *repo,\n \tget_common_dir_noenv(&sb, gitdir);\n \trefs->gitcommondir = strbuf_detach(&sb, NULL);\n \trefs->packed_ref_store =\n-\t\tpacked_ref_store_create(repo, refs->gitcommondir, flags);\n+\t\tpacked_ref_store_init(repo, refs->gitcommondir, flags);\n \n \tchdir_notify_reparent(\"files-backend $GIT_DIR\", &refs->base.gitdir);\n \tchdir_notify_reparent(\"files-backend $GIT_COMMONDIR\",\n@@ -3283,7 +3283,7 @@ static int files_init_db(struct ref_store *ref_store,\n \n struct ref_storage_be refs_be_files = {\n \t.name = \"files\",\n-\t.init = files_ref_store_create,\n+\t.init = files_ref_store_init,\n \t.init_db = files_init_db,\n \t.transaction_prepare = files_transaction_prepare,\n \t.transaction_finish = files_transaction_finish,\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex 4e826c05ff..a3c5a75073 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -200,9 +200,9 @@ static int release_snapshot(struct snapshot *snapshot)\n \t}\n }\n \n-struct ref_store *packed_ref_store_create(struct repository *repo,\n-\t\t\t\t\t  const char *gitdir,\n-\t\t\t\t\t  unsigned int store_flags)\n+struct ref_store *packed_ref_store_init(struct repository *repo,\n+\t\t\t\t\tconst char *gitdir,\n+\t\t\t\t\tunsigned int store_flags)\n {\n \tstruct packed_ref_store *refs = xcalloc(1, sizeof(*refs));\n \tstruct ref_store *ref_store = (struct ref_store *)refs;\n@@ -1244,9 +1244,9 @@ int packed_refs_is_locked(struct ref_store *ref_store)\n static const char PACKED_REFS_HEADER[] =\n \t\"# pack-refs with: peeled fully-peeled sorted \\n\";\n \n-static int packed_init_db(struct ref_store *ref_store UNUSED,\n-\t\t\t  int flags UNUSED,\n-\t\t\t  struct strbuf *err UNUSED)\n+static int packed_ref_store_init_db(struct ref_store *ref_store UNUSED,\n+\t\t\t\t    int flags UNUSED,\n+\t\t\t\t    struct strbuf *err UNUSED)\n {\n \t/* Nothing to do. */\n \treturn 0;\n@@ -1706,8 +1706,8 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s\n \n struct ref_storage_be refs_be_packed = {\n \t.name = \"packed\",\n-\t.init = packed_ref_store_create,\n-\t.init_db = packed_init_db,\n+\t.init = packed_ref_store_init,\n+\t.init_db = packed_ref_store_init_db,\n \t.transaction_prepare = packed_transaction_prepare,\n \t.transaction_finish = packed_transaction_finish,\n \t.transaction_abort = packed_transaction_abort,\ndiff --git a/refs/packed-backend.h b/refs/packed-backend.h\nindex 9dd8a344c3..09437ad13b 100644\n--- a/refs/packed-backend.h\n+++ b/refs/packed-backend.h\n@@ -13,9 +13,9 @@ struct ref_transaction;\n  * even among packed refs.\n  */\n \n-struct ref_store *packed_ref_store_create(struct repository *repo,\n-\t\t\t\t\t  const char *gitdir,\n-\t\t\t\t\t  unsigned int store_flags);\n+struct ref_store *packed_ref_store_init(struct repository *repo,\n+\t\t\t\t\tconst char *gitdir,\n+\t\t\t\t\tunsigned int store_flags);\n \n /*\n  * Lock the packed-refs file for writing. Flags is passed to\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494942","messageId":"050fb24e5834fab6e42ed7deda1e9380701db118.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 02/16] refs: rename `init_db` callback to avoid confusion","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:19Z","receivedAt":"2024-05-17T08:18:24Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Reference backends have two callbacks `init` and `init_db`. The\nsimilarity of these two callbacks has repeatedly confused me whenever I\nwas looking at them, where I always had to look up which of them does\nwhat.\n\nRename the `init_db` callback to `create_on_disk`, which should\nhopefully be clearer.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/worktree.c      |  2 +-\n refs.c                  |  4 ++--\n refs.h                  |  4 ++--\n refs/debug.c            |  8 ++++----\n refs/files-backend.c    | 12 ++++++------\n refs/packed-backend.c   |  8 ++++----\n refs/refs-internal.h    |  8 ++++----\n refs/reftable-backend.c | 10 +++++-----\n setup.c                 |  2 +-\n 9 files changed, 29 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 108cfa156a..49d9632aa8 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -509,7 +509,7 @@ static int add_worktree(const char *path, const char *refname,\n \t}\n \twt_refs = get_worktree_ref_store(wt);\n \n-\tret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);\n+\tret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);\n \tif (ret)\n \t\tgoto done;\n \ndiff --git a/refs.c b/refs.c\nindex a26c50a401..ebc6de81e9 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1938,9 +1938,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,\n }\n \n /* backend functions */\n-int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n+int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n {\n-\treturn refs->be->init_db(refs, flags, err);\n+\treturn refs->be->create_on_disk(refs, flags, err);\n }\n \n int resolve_gitlink_ref(const char *submodule, const char *refname,\ndiff --git a/refs.h b/refs.h\nindex d02dd79ca6..421ff9fdb7 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -114,9 +114,9 @@ int should_autocreate_reflog(const char *refname);\n \n int is_branch(const char *refname);\n \n-#define REFS_INIT_DB_IS_WORKTREE (1 << 0)\n+#define REF_STORE_CREATE_ON_DISK_IS_WORKTREE (1 << 0)\n \n-int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);\n+int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);\n \n /*\n  * Return the peeled value of the oid currently being iterated via\ndiff --git a/refs/debug.c b/refs/debug.c\nindex c7531b17f0..4cc4910974 100644\n--- a/refs/debug.c\n+++ b/refs/debug.c\n@@ -33,11 +33,11 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor\n \treturn (struct ref_store *)res;\n }\n \n-static int debug_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n+static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n {\n \tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n-\tint res = drefs->refs->be->init_db(drefs->refs, flags, err);\n-\ttrace_printf_key(&trace_refs, \"init_db: %d\\n\", res);\n+\tint res = drefs->refs->be->create_on_disk(drefs->refs, flags, err);\n+\ttrace_printf_key(&trace_refs, \"create_on_disk: %d\\n\", res);\n \treturn res;\n }\n \n@@ -427,7 +427,7 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,\n struct ref_storage_be refs_be_debug = {\n \t.name = \"debug\",\n \t.init = NULL,\n-\t.init_db = debug_init_db,\n+\t.create_on_disk = debug_create_on_disk,\n \n \t/*\n \t * None of these should be NULL. If the \"files\" backend (in\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 2c9d5e0747..f9f15d1f76 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3236,12 +3236,12 @@ static int files_reflog_expire(struct ref_store *ref_store,\n \treturn -1;\n }\n \n-static int files_init_db(struct ref_store *ref_store,\n-\t\t\t int flags,\n-\t\t\t struct strbuf *err UNUSED)\n+static int files_ref_store_create_on_disk(struct ref_store *ref_store,\n+\t\t\t\t\t  int flags,\n+\t\t\t\t\t  struct strbuf *err UNUSED)\n {\n \tstruct files_ref_store *refs =\n-\t\tfiles_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n+\t\tfiles_downcast(ref_store, REF_STORE_WRITE, \"create\");\n \tstruct strbuf sb = STRBUF_INIT;\n \n \t/*\n@@ -3264,7 +3264,7 @@ static int files_init_db(struct ref_store *ref_store,\n \t * There is no need to create directories for common refs when creating\n \t * a worktree ref store.\n \t */\n-\tif (!(flags & REFS_INIT_DB_IS_WORKTREE)) {\n+\tif (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {\n \t\t/*\n \t\t * Create .git/refs/{heads,tags}\n \t\t */\n@@ -3284,7 +3284,7 @@ static int files_init_db(struct ref_store *ref_store,\n struct ref_storage_be refs_be_files = {\n \t.name = \"files\",\n \t.init = files_ref_store_init,\n-\t.init_db = files_init_db,\n+\t.create_on_disk = files_ref_store_create_on_disk,\n \t.transaction_prepare = files_transaction_prepare,\n \t.transaction_finish = files_transaction_finish,\n \t.transaction_abort = files_transaction_abort,\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex a3c5a75073..b94183034e 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -1244,9 +1244,9 @@ int packed_refs_is_locked(struct ref_store *ref_store)\n static const char PACKED_REFS_HEADER[] =\n \t\"# pack-refs with: peeled fully-peeled sorted \\n\";\n \n-static int packed_ref_store_init_db(struct ref_store *ref_store UNUSED,\n-\t\t\t\t    int flags UNUSED,\n-\t\t\t\t    struct strbuf *err UNUSED)\n+static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED,\n+\t\t\t\t\t   int flags UNUSED,\n+\t\t\t\t\t   struct strbuf *err UNUSED)\n {\n \t/* Nothing to do. */\n \treturn 0;\n@@ -1707,7 +1707,7 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s\n struct ref_storage_be refs_be_packed = {\n \t.name = \"packed\",\n \t.init = packed_ref_store_init,\n-\t.init_db = packed_ref_store_init_db,\n+\t.create_on_disk = packed_ref_store_create_on_disk,\n \t.transaction_prepare = packed_transaction_prepare,\n \t.transaction_finish = packed_transaction_finish,\n \t.transaction_abort = packed_transaction_abort,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 56641aa57a..c3d5f0a6cd 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -530,9 +530,9 @@ typedef struct ref_store *ref_store_init_fn(struct repository *repo,\n \t\t\t\t\t    const char *gitdir,\n \t\t\t\t\t    unsigned int flags);\n \n-typedef int ref_init_db_fn(struct ref_store *refs,\n-\t\t\t   int flags,\n-\t\t\t   struct strbuf *err);\n+typedef int ref_store_create_on_disk_fn(struct ref_store *refs,\n+\t\t\t\t\tint flags,\n+\t\t\t\t\tstruct strbuf *err);\n \n typedef int ref_transaction_prepare_fn(struct ref_store *refs,\n \t\t\t\t       struct ref_transaction *transaction,\n@@ -668,7 +668,7 @@ typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam\n struct ref_storage_be {\n \tconst char *name;\n \tref_store_init_fn *init;\n-\tref_init_db_fn *init_db;\n+\tref_store_create_on_disk_fn *create_on_disk;\n \n \tref_transaction_prepare_fn *transaction_prepare;\n \tref_transaction_finish_fn *transaction_finish;\ndiff --git a/refs/reftable-backend.c b/refs/reftable-backend.c\nindex 010ef811b6..8583a0cdba 100644\n--- a/refs/reftable-backend.c\n+++ b/refs/reftable-backend.c\n@@ -293,12 +293,12 @@ static struct ref_store *reftable_be_init(struct repository *repo,\n \treturn &refs->base;\n }\n \n-static int reftable_be_init_db(struct ref_store *ref_store,\n-\t\t\t       int flags UNUSED,\n-\t\t\t       struct strbuf *err UNUSED)\n+static int reftable_be_create_on_disk(struct ref_store *ref_store,\n+\t\t\t\t      int flags UNUSED,\n+\t\t\t\t      struct strbuf *err UNUSED)\n {\n \tstruct reftable_ref_store *refs =\n-\t\treftable_be_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n+\t\treftable_be_downcast(ref_store, REF_STORE_WRITE, \"create\");\n \tstruct strbuf sb = STRBUF_INIT;\n \n \tstrbuf_addf(&sb, \"%s/reftable\", refs->base.gitdir);\n@@ -2248,7 +2248,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,\n struct ref_storage_be refs_be_reftable = {\n \t.name = \"reftable\",\n \t.init = reftable_be_init,\n-\t.init_db = reftable_be_init_db,\n+\t.create_on_disk = reftable_be_create_on_disk,\n \t.transaction_prepare = reftable_be_transaction_prepare,\n \t.transaction_finish = reftable_be_transaction_finish,\n \t.transaction_abort = reftable_be_transaction_abort,\ndiff --git a/setup.c b/setup.c\nindex c7d3375645..fec6bfd5fa 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2049,7 +2049,7 @@ void create_reference_database(unsigned int ref_storage_format,\n \tint reinit = is_reinit();\n \n \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n-\tif (refs_init_db(get_main_ref_store(the_repository), 0, &err))\n+\tif (ref_store_create_on_disk(get_main_ref_store(the_repository), 0, &err))\n \t\tdie(\"failed to set up refs db: %s\", err.buf);\n \n \t/*\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494943","messageId":"4beecb09445f050eecaff079d7cc873ddce62706.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 03/16] refs: implement releasing ref storages","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:24Z","receivedAt":"2024-05-17T08:18:30Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Ref storages are typically only initialized once for `the_repository`\nand then never released. Until now we got away with that without causing\nmemory leaks because `the_repository` stays reachable, and because the\nref backend is reachable via `the_repository` its memory basically never\nleaks.\n\nThis is about to change though because of the upcoming migration logic,\nwhich will create a secondary ref storage. In that case, we will either\nhave to release the old or new ref storage to avoid leaks.\n\nImplement a new `release` callback and expose it via a new\n`ref_storage_release()` function.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.c                  |  6 ++++++\n refs.h                  |  5 +++++\n refs/debug.c            |  8 ++++++++\n refs/files-backend.c    | 10 ++++++++++\n refs/packed-backend.c   | 11 +++++++++++\n refs/refs-internal.h    |  5 +++++\n refs/reftable-backend.c | 23 +++++++++++++++++++++++\n 7 files changed, 68 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex ebc6de81e9..0f4d327c47 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2041,6 +2041,12 @@ static struct ref_store *ref_store_init(struct repository *repo,\n \treturn refs;\n }\n \n+void ref_store_release(struct ref_store *ref_store)\n+{\n+\tref_store->be->release(ref_store);\n+\tfree(ref_store->gitdir);\n+}\n+\n struct ref_store *get_main_ref_store(struct repository *r)\n {\n \tif (r->refs_private)\ndiff --git a/refs.h b/refs.h\nindex 421ff9fdb7..b11c250e8a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -118,6 +118,11 @@ int is_branch(const char *refname);\n \n int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err);\n \n+/*\n+ * Release all memory and resources associated with the ref store.\n+ */\n+void ref_store_release(struct ref_store *ref_store);\n+\n /*\n  * Return the peeled value of the oid currently being iterated via\n  * for_each_ref(), etc. This is equivalent to calling:\ndiff --git a/refs/debug.c b/refs/debug.c\nindex 4cc4910974..3a063077ba 100644\n--- a/refs/debug.c\n+++ b/refs/debug.c\n@@ -33,6 +33,13 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor\n \treturn (struct ref_store *)res;\n }\n \n+static void debug_release(struct ref_store *refs)\n+{\n+\tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n+\tdrefs->refs->be->release(drefs->refs);\n+\ttrace_printf_key(&trace_refs, \"release\\n\");\n+}\n+\n static int debug_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)\n {\n \tstruct debug_ref_store *drefs = (struct debug_ref_store *)refs;\n@@ -427,6 +434,7 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,\n struct ref_storage_be refs_be_debug = {\n \t.name = \"debug\",\n \t.init = NULL,\n+\t.release = debug_release,\n \t.create_on_disk = debug_create_on_disk,\n \n \t/*\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex f9f15d1f76..62acd2721d 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -149,6 +149,14 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,\n \treturn refs;\n }\n \n+static void files_ref_store_release(struct ref_store *ref_store)\n+{\n+\tstruct files_ref_store *refs = files_downcast(ref_store, 0, \"release\");\n+\tfree_ref_cache(refs->loose);\n+\tfree(refs->gitcommondir);\n+\tref_store_release(refs->packed_ref_store);\n+}\n+\n static void files_reflog_path(struct files_ref_store *refs,\n \t\t\t      struct strbuf *sb,\n \t\t\t      const char *refname)\n@@ -3284,7 +3292,9 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,\n struct ref_storage_be refs_be_files = {\n \t.name = \"files\",\n \t.init = files_ref_store_init,\n+\t.release = files_ref_store_release,\n \t.create_on_disk = files_ref_store_create_on_disk,\n+\n \t.transaction_prepare = files_transaction_prepare,\n \t.transaction_finish = files_transaction_finish,\n \t.transaction_abort = files_transaction_abort,\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex b94183034e..9c98e6295f 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -252,6 +252,15 @@ static void clear_snapshot(struct packed_ref_store *refs)\n \t}\n }\n \n+static void packed_ref_store_release(struct ref_store *ref_store)\n+{\n+\tstruct packed_ref_store *refs = packed_downcast(ref_store, 0, \"release\");\n+\tclear_snapshot(refs);\n+\trollback_lock_file(&refs->lock);\n+\tdelete_tempfile(&refs->tempfile);\n+\tfree(refs->path);\n+}\n+\n static NORETURN void die_unterminated_line(const char *path,\n \t\t\t\t\t   const char *p, size_t len)\n {\n@@ -1707,7 +1716,9 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s\n struct ref_storage_be refs_be_packed = {\n \t.name = \"packed\",\n \t.init = packed_ref_store_init,\n+\t.release = packed_ref_store_release,\n \t.create_on_disk = packed_ref_store_create_on_disk,\n+\n \t.transaction_prepare = packed_transaction_prepare,\n \t.transaction_finish = packed_transaction_finish,\n \t.transaction_abort = packed_transaction_abort,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex c3d5f0a6cd..8624477e19 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -529,6 +529,10 @@ struct ref_store;\n typedef struct ref_store *ref_store_init_fn(struct repository *repo,\n \t\t\t\t\t    const char *gitdir,\n \t\t\t\t\t    unsigned int flags);\n+/*\n+ * Release all memory and resources associated with the ref store.\n+ */\n+typedef void ref_store_release_fn(struct ref_store *refs);\n \n typedef int ref_store_create_on_disk_fn(struct ref_store *refs,\n \t\t\t\t\tint flags,\n@@ -668,6 +672,7 @@ typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam\n struct ref_storage_be {\n \tconst char *name;\n \tref_store_init_fn *init;\n+\tref_store_release_fn *release;\n \tref_store_create_on_disk_fn *create_on_disk;\n \n \tref_transaction_prepare_fn *transaction_prepare;\ndiff --git a/refs/reftable-backend.c b/refs/reftable-backend.c\nindex 8583a0cdba..7b73f73f59 100644\n--- a/refs/reftable-backend.c\n+++ b/refs/reftable-backend.c\n@@ -293,6 +293,27 @@ static struct ref_store *reftable_be_init(struct repository *repo,\n \treturn &refs->base;\n }\n \n+static void reftable_be_release(struct ref_store *ref_store)\n+{\n+\tstruct reftable_ref_store *refs = reftable_be_downcast(ref_store, 0, \"release\");\n+\tstruct strmap_entry *entry;\n+\tstruct hashmap_iter iter;\n+\n+\tif (refs->main_stack) {\n+\t\treftable_stack_destroy(refs->main_stack);\n+\t\trefs->main_stack = NULL;\n+\t}\n+\n+\tif (refs->worktree_stack) {\n+\t\treftable_stack_destroy(refs->worktree_stack);\n+\t\trefs->worktree_stack = NULL;\n+\t}\n+\n+\tstrmap_for_each_entry(&refs->worktree_stacks, &iter, entry)\n+\t\treftable_stack_destroy(entry->value);\n+\tstrmap_clear(&refs->worktree_stacks, 0);\n+}\n+\n static int reftable_be_create_on_disk(struct ref_store *ref_store,\n \t\t\t\t      int flags UNUSED,\n \t\t\t\t      struct strbuf *err UNUSED)\n@@ -2248,7 +2269,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,\n struct ref_storage_be refs_be_reftable = {\n \t.name = \"reftable\",\n \t.init = reftable_be_init,\n+\t.release = reftable_be_release,\n \t.create_on_disk = reftable_be_create_on_disk,\n+\n \t.transaction_prepare = reftable_be_transaction_prepare,\n \t.transaction_finish = reftable_be_transaction_finish,\n \t.transaction_abort = reftable_be_transaction_abort,\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494944","messageId":"9ca54a12e892a188ba54922c8cbb0e8ceffab0f4.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 04/16] refs: track ref stores via strmap","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:28Z","receivedAt":"2024-05-17T08:18:33Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The refs code has two global maps that track the submodule and worktree\nref stores. Even though both of these maps track values by strings, we\nstill use a `struct hashmap` instead of a `struct strmap`. This has the\nbenefit of saving us an allocation because we can combine key and value\nin a single struct. But it does introduce significant complexity that is\ncompletely unneeded.\n\nRefactor the code to use `struct strmap`s instead to reduce complexity.\nIt's unlikely that this will have any real-world impact on performance\ngiven that most repositories likely won't have all that many ref stores.\nFurthermore, this refactoring allows us to de-globalize those maps and\nmove them into `struct repository` in a subsequent commit more easily.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.c | 71 ++++++++++++----------------------------------------------\n 1 file changed, 14 insertions(+), 57 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 0f4d327c47..01e8453930 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -6,7 +6,7 @@\n #include \"advice.h\"\n #include \"config.h\"\n #include \"environment.h\"\n-#include \"hashmap.h\"\n+#include \"strmap.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"lockfile.h\"\n@@ -1960,66 +1960,27 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,\n \treturn 0;\n }\n \n-struct ref_store_hash_entry\n-{\n-\tstruct hashmap_entry ent;\n-\n-\tstruct ref_store *refs;\n-\n-\t/* NUL-terminated identifier of the ref store: */\n-\tchar name[FLEX_ARRAY];\n-};\n+/* A strmap of ref_stores, stored by submodule name: */\n+static struct strmap submodule_ref_stores;\n \n-static int ref_store_hash_cmp(const void *cmp_data UNUSED,\n-\t\t\t      const struct hashmap_entry *eptr,\n-\t\t\t      const struct hashmap_entry *entry_or_key,\n-\t\t\t      const void *keydata)\n-{\n-\tconst struct ref_store_hash_entry *e1, *e2;\n-\tconst char *name;\n-\n-\te1 = container_of(eptr, const struct ref_store_hash_entry, ent);\n-\te2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);\n-\tname = keydata ? keydata : e2->name;\n-\n-\treturn strcmp(e1->name, name);\n-}\n-\n-static struct ref_store_hash_entry *alloc_ref_store_hash_entry(\n-\t\tconst char *name, struct ref_store *refs)\n-{\n-\tstruct ref_store_hash_entry *entry;\n-\n-\tFLEX_ALLOC_STR(entry, name, name);\n-\thashmap_entry_init(&entry->ent, strhash(name));\n-\tentry->refs = refs;\n-\treturn entry;\n-}\n-\n-/* A hashmap of ref_stores, stored by submodule name: */\n-static struct hashmap submodule_ref_stores;\n-\n-/* A hashmap of ref_stores, stored by worktree id: */\n-static struct hashmap worktree_ref_stores;\n+/* A strmap of ref_stores, stored by worktree id: */\n+static struct strmap worktree_ref_stores;\n \n /*\n  * Look up a ref store by name. If that ref_store hasn't been\n  * registered yet, return NULL.\n  */\n-static struct ref_store *lookup_ref_store_map(struct hashmap *map,\n+static struct ref_store *lookup_ref_store_map(struct strmap *map,\n \t\t\t\t\t      const char *name)\n {\n-\tstruct ref_store_hash_entry *entry;\n-\tunsigned int hash;\n+\tstruct strmap_entry *entry;\n \n-\tif (!map->tablesize)\n+\tif (!map->map.tablesize)\n \t\t/* It's initialized on demand in register_ref_store(). */\n \t\treturn NULL;\n \n-\thash = strhash(name);\n-\tentry = hashmap_get_entry_from_hash(map, hash, name,\n-\t\t\t\t\tstruct ref_store_hash_entry, ent);\n-\treturn entry ? entry->refs : NULL;\n+\tentry = strmap_get_entry(map, name);\n+\treturn entry ? entry->value : NULL;\n }\n \n /*\n@@ -2064,18 +2025,14 @@ struct ref_store *get_main_ref_store(struct repository *r)\n  * Associate a ref store with a name. It is a fatal error to call this\n  * function twice for the same name.\n  */\n-static void register_ref_store_map(struct hashmap *map,\n+static void register_ref_store_map(struct strmap *map,\n \t\t\t\t   const char *type,\n \t\t\t\t   struct ref_store *refs,\n \t\t\t\t   const char *name)\n {\n-\tstruct ref_store_hash_entry *entry;\n-\n-\tif (!map->tablesize)\n-\t\thashmap_init(map, ref_store_hash_cmp, NULL, 0);\n-\n-\tentry = alloc_ref_store_hash_entry(name, refs);\n-\tif (hashmap_put(map, &entry->ent))\n+\tif (!map->map.tablesize)\n+\t\tstrmap_init(map);\n+\tif (strmap_put(map, name, refs))\n \t\tBUG(\"%s ref_store '%s' initialized twice\", type, name);\n }\n \n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494945","messageId":"d7f8b2f40db4cf586aa5a2bdd038284ae6d1c9d8.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 05/16] refs: pass repo when retrieving submodule ref store","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:34Z","receivedAt":"2024-05-17T08:18:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Looking up submodule ref stores has two deficiencies:\n\n  - The initialized subrepo will be attributed to `the_repository`.\n\n  - The submodule ref store will be tracked in a global map.\n\nThis makes it impossible to have submodule ref stores for a repository\nother than `the_repository`.\n\nModify the function to accept the parent repository as parameter and\nmove the global map into `struct repository`. Like this it becomes\npossible to look up submodule ref stores for arbitrary repositories.\n\nNote that this also adds a new reference to `the_repository` in\n`resolve_gitlink_ref()`, which is part of the refs interfaces. This will\nget adjusted in the next patch.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/submodule--helper.c |  6 ++++--\n refs.c                      | 22 +++++++---------------\n refs.h                      |  3 ++-\n refs/refs-internal.h        |  2 +-\n repository.c                |  8 ++++++++\n repository.h                |  8 ++++++++\n submodule.c                 |  3 ++-\n t/helper/test-ref-store.c   |  2 +-\n 8 files changed, 33 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e604cb5ddb..5076a33500 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -679,7 +679,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     displaypath);\n \t} else if (!(flags & OPT_CACHED)) {\n \t\tstruct object_id oid;\n-\t\tstruct ref_store *refs = get_submodule_ref_store(path);\n+\t\tstruct ref_store *refs = repo_get_submodule_ref_store(the_repository,\n+\t\t\t\t\t\t\t\t      path);\n \n \t\tif (!refs) {\n \t\t\tprint_status(flags, '-', path, ce_oid, displaypath);\n@@ -903,7 +904,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n-\t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n+\t\t\tstruct ref_store *refs = repo_get_submodule_ref_store(the_repository,\n+\t\t\t\t\t\t\t\t\t      p->sm_path);\n \n \t\t\tif (refs)\n \t\t\t\trefs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);\ndiff --git a/refs.c b/refs.c\nindex 01e8453930..1d660d5ace 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1949,8 +1949,7 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,\n \tstruct ref_store *refs;\n \tint flags;\n \n-\trefs = get_submodule_ref_store(submodule);\n-\n+\trefs = repo_get_submodule_ref_store(the_repository, submodule);\n \tif (!refs)\n \t\treturn -1;\n \n@@ -1960,9 +1959,6 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,\n \treturn 0;\n }\n \n-/* A strmap of ref_stores, stored by submodule name: */\n-static struct strmap submodule_ref_stores;\n-\n /* A strmap of ref_stores, stored by worktree id: */\n static struct strmap worktree_ref_stores;\n \n@@ -2036,7 +2032,8 @@ static void register_ref_store_map(struct strmap *map,\n \t\tBUG(\"%s ref_store '%s' initialized twice\", type, name);\n }\n \n-struct ref_store *get_submodule_ref_store(const char *submodule)\n+struct ref_store *repo_get_submodule_ref_store(struct repository *repo,\n+\t\t\t\t\t       const char *submodule)\n {\n \tstruct strbuf submodule_sb = STRBUF_INIT;\n \tstruct ref_store *refs;\n@@ -2057,7 +2054,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \t\t/* We need to strip off one or more trailing slashes */\n \t\tsubmodule = to_free = xmemdupz(submodule, len);\n \n-\trefs = lookup_ref_store_map(&submodule_ref_stores, submodule);\n+\trefs = lookup_ref_store_map(&repo->submodule_ref_stores, submodule);\n \tif (refs)\n \t\tgoto done;\n \n@@ -2069,20 +2066,15 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \t\tgoto done;\n \n \tsubrepo = xmalloc(sizeof(*subrepo));\n-\t/*\n-\t * NEEDSWORK: Make get_submodule_ref_store() work with arbitrary\n-\t * superprojects other than the_repository. This probably should be\n-\t * done by making it take a struct repository * parameter instead of a\n-\t * submodule path.\n-\t */\n-\tif (repo_submodule_init(subrepo, the_repository, submodule,\n+\n+\tif (repo_submodule_init(subrepo, repo, submodule,\n \t\t\t\tnull_oid())) {\n \t\tfree(subrepo);\n \t\tgoto done;\n \t}\n \trefs = ref_store_init(subrepo, submodule_sb.buf,\n \t\t\t      REF_STORE_READ | REF_STORE_ODB);\n-\tregister_ref_store_map(&submodule_ref_stores, \"submodule\",\n+\tregister_ref_store_map(&repo->submodule_ref_stores, \"submodule\",\n \t\t\t       refs, submodule);\n \n done:\ndiff --git a/refs.h b/refs.h\nindex b11c250e8a..346a81e9e3 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -954,7 +954,8 @@ struct ref_store *get_main_ref_store(struct repository *r);\n  * For backwards compatibility, submodule==\"\" is treated the same as\n  * submodule==NULL.\n  */\n-struct ref_store *get_submodule_ref_store(const char *submodule);\n+struct ref_store *repo_get_submodule_ref_store(struct repository *repo,\n+\t\t\t\t\t       const char *submodule);\n struct ref_store *get_worktree_ref_store(const struct worktree *wt);\n \n /*\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 8624477e19..178a355eb0 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -705,7 +705,7 @@ extern struct ref_storage_be refs_be_packed;\n /*\n  * A representation of the reference store for the main repository or\n  * a submodule. The ref_store instances for submodules are kept in a\n- * hash map; see get_submodule_ref_store() for more info.\n+ * hash map; see repo_get_submodule_ref_store() for more info.\n  */\n struct ref_store {\n \t/* The backend describing this ref_store's storage scheme: */\ndiff --git a/repository.c b/repository.c\nindex c50849fd83..bb9b9e2b52 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -14,6 +14,7 @@\n #include \"sparse-index.h\"\n #include \"trace2.h\"\n #include \"promisor-remote.h\"\n+#include \"refs.h\"\n \n /* The main repository */\n static struct repository the_repo;\n@@ -289,6 +290,9 @@ static void repo_clear_path_cache(struct repo_path_cache *cache)\n \n void repo_clear(struct repository *repo)\n {\n+\tstruct hashmap_iter iter;\n+\tstruct strmap_entry *e;\n+\n \tFREE_AND_NULL(repo->gitdir);\n \tFREE_AND_NULL(repo->commondir);\n \tFREE_AND_NULL(repo->graft_file);\n@@ -329,6 +333,10 @@ void repo_clear(struct repository *repo)\n \t\tFREE_AND_NULL(repo->remote_state);\n \t}\n \n+\tstrmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)\n+\t\tref_store_release(e->value);\n+\tstrmap_clear(&repo->submodule_ref_stores, 1);\n+\n \trepo_clear_path_cache(&repo->cached_paths);\n }\n \ndiff --git a/repository.h b/repository.h\nindex 41ed22543a..0389df0461 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,8 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+#include \"strmap.h\"\n+\n struct config_set;\n struct fsmonitor_settings;\n struct git_hash_algo;\n@@ -108,6 +110,12 @@ struct repository {\n \t */\n \tstruct ref_store *refs_private;\n \n+\t/*\n+\t * A strmap of ref_stores, stored by submodule name, accessible via\n+\t * `repo_get_submodule_ref_store()`.\n+\t */\n+\tstruct strmap submodule_ref_stores;\n+\n \t/*\n \t * Contains path to often used file names.\n \t */\ndiff --git a/submodule.c b/submodule.c\nindex f6313cd99f..759cf1e1cd 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -99,7 +99,8 @@ int is_staging_gitmodules_ok(struct index_state *istate)\n static int for_each_remote_ref_submodule(const char *submodule,\n \t\t\t\t\t each_ref_fn fn, void *cb_data)\n {\n-\treturn refs_for_each_remote_ref(get_submodule_ref_store(submodule),\n+\treturn refs_for_each_remote_ref(repo_get_submodule_ref_store(the_repository,\n+\t\t\t\t\t\t\t\t     submodule),\n \t\t\t\t\tfn, cb_data);\n }\n \ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 82bbf6e2e6..a5a7609811 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -82,7 +82,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)\n \t\tadd_to_alternates_memory(sb.buf);\n \t\tstrbuf_release(&sb);\n \n-\t\t*refs = get_submodule_ref_store(gitdir);\n+\t\t*refs = repo_get_submodule_ref_store(the_repository, gitdir);\n \t} else if (skip_prefix(argv[0], \"worktree:\", &gitdir)) {\n \t\tstruct worktree **p, **worktrees = get_worktrees();\n \n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494946","messageId":"a8593b16a6ef85ede315f8937a6d447a03a46635.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 06/16] refs: refactor `resolve_gitlink_ref()` to accept a repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:39Z","receivedAt":"2024-05-17T08:18:44Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"In `resolve_gitlink_ref()` we implicitly rely on `the_repository` to\nlook up the submodule ref store. Now that we can look up submodule ref\nstores for arbitrary repositories we can improve this function to\ninstead accept a repository as parameter for which we want to resolve\nthe gitlink.\n\nDo so and adjust callers accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n attr.c                      | 3 ++-\n builtin/submodule--helper.c | 8 +++++---\n builtin/update-index.c      | 5 +++--\n combine-diff.c              | 3 ++-\n diff-lib.c                  | 3 ++-\n dir.c                       | 3 ++-\n object-file.c               | 2 +-\n read-cache.c                | 5 +++--\n refs.c                      | 7 ++++---\n refs.h                      | 5 +++--\n unpack-trees.c              | 3 ++-\n 11 files changed, 29 insertions(+), 18 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 33473bdce0..6c6eb05333 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -1288,7 +1288,8 @@ static const char *builtin_object_mode_attr(struct index_state *istate, const ch\n \t\t\tif (pos >= 0) {\n \t\t\t\t if (S_ISGITLINK(istate->cache[pos]->ce_mode))\n \t\t\t\t\t mode = istate->cache[pos]->ce_mode;\n-\t\t\t} else if (resolve_gitlink_ref(path, \"HEAD\", &oid) == 0) {\n+\t\t\t} else if (repo_resolve_gitlink_ref(the_repository, path,\n+\t\t\t\t\t\t\t    \"HEAD\", &oid) == 0) {\n \t\t\t\tmode = S_IFGITLINK;\n \t\t\t}\n \t\t}\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5076a33500..897f19868e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2600,7 +2600,8 @@ static int update_submodule(struct update_data *update_data)\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n-\telse if (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\telse if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,\n+\t\t\t\t\t  \"HEAD\", &update_data->suboid))\n \t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n \t\t\t\t   update_data->displaypath);\n \n@@ -2627,7 +2628,8 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t\t\t   update_data->sm_path);\n \t\t}\n \n-\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\tif (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,\n+\t\t\t\t\t     remote_ref, &update_data->oid))\n \t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n \t\t\t\t\t   remote_ref, update_data->sm_path);\n \n@@ -3357,7 +3359,7 @@ static void die_on_repo_without_commits(const char *path)\n \tstrbuf_addstr(&sb, path);\n \tif (is_nonbare_repository_dir(&sb)) {\n \t\tstruct object_id oid;\n-\t\tif (resolve_gitlink_ref(path, \"HEAD\", &oid) < 0)\n+\t\tif (repo_resolve_gitlink_ref(the_repository, path, \"HEAD\", &oid) < 0)\n \t\t\tdie(_(\"'%s' does not have a commit checked out\"), path);\n \t}\n \tstrbuf_release(&sb);\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 20aa1c4c68..d343416ae2 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -349,7 +349,8 @@ static int process_directory(const char *path, int len, struct stat *st)\n \t\tif (S_ISGITLINK(ce->ce_mode)) {\n \n \t\t\t/* Do nothing to the index if there is no HEAD! */\n-\t\t\tif (resolve_gitlink_ref(path, \"HEAD\", &oid) < 0)\n+\t\t\tif (repo_resolve_gitlink_ref(the_repository, path,\n+\t\t\t\t\t\t     \"HEAD\", &oid) < 0)\n \t\t\t\treturn 0;\n \n \t\t\treturn add_one_path(ce, path, len, st);\n@@ -375,7 +376,7 @@ static int process_directory(const char *path, int len, struct stat *st)\n \t}\n \n \t/* No match - should we add it as a gitlink? */\n-\tif (!resolve_gitlink_ref(path, \"HEAD\", &oid))\n+\tif (!repo_resolve_gitlink_ref(the_repository, path, \"HEAD\", &oid))\n \t\treturn add_one_path(NULL, path, len, st);\n \n \t/* Error out. */\ndiff --git a/combine-diff.c b/combine-diff.c\nindex d6d6fa1689..4960d904ac 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1066,7 +1066,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\telem->mode = canon_mode(st.st_mode);\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstruct object_id oid;\n-\t\t\tif (resolve_gitlink_ref(elem->path, \"HEAD\", &oid) < 0)\n+\t\t\tif (repo_resolve_gitlink_ref(the_repository, elem->path,\n+\t\t\t\t\t\t     \"HEAD\", &oid) < 0)\n \t\t\t\tresult = grab_blob(opt->repo, &elem->oid,\n \t\t\t\t\t\t   elem->mode, &result_size,\n \t\t\t\t\t\t   NULL, NULL);\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 12b1541478..5a5a50c5a1 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -66,7 +66,8 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)\n \t\t * a directory --- the blob was removed!\n \t\t */\n \t\tif (!S_ISGITLINK(ce->ce_mode) &&\n-\t\t    resolve_gitlink_ref(ce->name, \"HEAD\", &sub))\n+\t\t    repo_resolve_gitlink_ref(the_repository, ce->name,\n+\t\t\t\t\t     \"HEAD\", &sub))\n \t\t\treturn 1;\n \t}\n \treturn 0;\ndiff --git a/dir.c b/dir.c\nindex 2d83f3311a..f6066cc01d 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3318,7 +3318,8 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)\n \tstruct object_id submodule_head;\n \n \tif ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&\n-\t    !resolve_gitlink_ref(path->buf, \"HEAD\", &submodule_head)) {\n+\t    !repo_resolve_gitlink_ref(the_repository, path->buf,\n+\t\t\t\t      \"HEAD\", &submodule_head)) {\n \t\t/* Do not descend and nuke a nested git work tree. */\n \t\tif (kept_up)\n \t\t\t*kept_up = 1;\ndiff --git a/object-file.c b/object-file.c\nindex 610b1f465c..a40300ce4a 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -2669,7 +2669,7 @@ int index_path(struct index_state *istate, struct object_id *oid,\n \t\tstrbuf_release(&sb);\n \t\tbreak;\n \tcase S_IFDIR:\n-\t\treturn resolve_gitlink_ref(path, \"HEAD\", oid);\n+\t\treturn repo_resolve_gitlink_ref(the_repository, path, \"HEAD\", oid);\n \tdefault:\n \t\treturn error(_(\"%s: unsupported file type\"), path);\n \t}\ndiff --git a/read-cache.c b/read-cache.c\nindex a6db25a16d..447109aa76 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -271,7 +271,8 @@ static int ce_compare_gitlink(const struct cache_entry *ce)\n \t *\n \t * If so, we consider it always to match.\n \t */\n-\tif (resolve_gitlink_ref(ce->name, \"HEAD\", &oid) < 0)\n+\tif (repo_resolve_gitlink_ref(the_repository, ce->name,\n+\t\t\t\t     \"HEAD\", &oid) < 0)\n \t\treturn 0;\n \treturn !oideq(&oid, &ce->oid);\n }\n@@ -711,7 +712,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \n \tnamelen = strlen(path);\n \tif (S_ISDIR(st_mode)) {\n-\t\tif (resolve_gitlink_ref(path, \"HEAD\", &oid) < 0)\n+\t\tif (repo_resolve_gitlink_ref(the_repository, path, \"HEAD\", &oid) < 0)\n \t\t\treturn error(_(\"'%s' does not have a commit checked out\"), path);\n \t\twhile (namelen && path[namelen-1] == '/')\n \t\t\tnamelen--;\ndiff --git a/refs.c b/refs.c\nindex 1d660d5ace..7703b7781c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1943,13 +1943,14 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e\n \treturn refs->be->create_on_disk(refs, flags, err);\n }\n \n-int resolve_gitlink_ref(const char *submodule, const char *refname,\n-\t\t\tstruct object_id *oid)\n+int repo_resolve_gitlink_ref(struct repository *r,\n+\t\t\t     const char *submodule, const char *refname,\n+\t\t\t     struct object_id *oid)\n {\n \tstruct ref_store *refs;\n \tint flags;\n \n-\trefs = repo_get_submodule_ref_store(the_repository, submodule);\n+\trefs = repo_get_submodule_ref_store(r, submodule);\n \tif (!refs)\n \t\treturn -1;\n \ndiff --git a/refs.h b/refs.h\nindex 346a81e9e3..90a7e2dde3 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -141,8 +141,9 @@ int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);\n  * successful, return 0 and set oid to the name of the object;\n  * otherwise, return a non-zero value.\n  */\n-int resolve_gitlink_ref(const char *submodule, const char *refname,\n-\t\t\tstruct object_id *oid);\n+int repo_resolve_gitlink_ref(struct repository *r,\n+\t\t\t     const char *submodule, const char *refname,\n+\t\t\t     struct object_id *oid);\n \n /*\n  * Return true iff abbrev_name is a possible abbreviation for\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex c2b20b80d5..304ea2ed86 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -2318,7 +2318,8 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,\n \n \tif (S_ISGITLINK(ce->ce_mode)) {\n \t\tstruct object_id oid;\n-\t\tint sub_head = resolve_gitlink_ref(ce->name, \"HEAD\", &oid);\n+\t\tint sub_head = repo_resolve_gitlink_ref(the_repository, ce->name,\n+\t\t\t\t\t\t\t\"HEAD\", &oid);\n \t\t/*\n \t\t * If we are not going to update the submodule, then\n \t\t * we don't care.\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494947","messageId":"977f3a8510c96b8f278852ef240e19c759a53d2c.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 07/16] refs: retrieve worktree ref stores via associated repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:44Z","receivedAt":"2024-05-17T08:18:49Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Similar as with the preceding commit, the worktree ref stores are always\nlooked up via `the_repository`. Also, again, those ref stores are stored\nin a global map.\n\nRefactor the code so that worktrees have a pointer to their repository.\nLike this, we can move the global map into `struct repository` and stop\nusing `the_repository`. With this change, we can now in theory look up\nworktree ref stores for repositories other than `the_repository`. In\npractice, the worktree code will need further changes to look up\narbitrary worktrees.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.c       | 27 ++++++++++++++-------------\n repository.c |  4 ++++\n repository.h |  6 ++++++\n worktree.c   |  2 ++\n worktree.h   |  2 ++\n 5 files changed, 28 insertions(+), 13 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 7703b7781c..70e712fcef 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1960,9 +1960,6 @@ int repo_resolve_gitlink_ref(struct repository *r,\n \treturn 0;\n }\n \n-/* A strmap of ref_stores, stored by worktree id: */\n-static struct strmap worktree_ref_stores;\n-\n /*\n  * Look up a ref store by name. If that ref_store hasn't been\n  * registered yet, return NULL.\n@@ -2091,25 +2088,29 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)\n \tconst char *id;\n \n \tif (wt->is_current)\n-\t\treturn get_main_ref_store(the_repository);\n+\t\treturn get_main_ref_store(wt->repo);\n \n \tid = wt->id ? wt->id : \"/\";\n-\trefs = lookup_ref_store_map(&worktree_ref_stores, id);\n+\trefs = lookup_ref_store_map(&wt->repo->worktree_ref_stores, id);\n \tif (refs)\n \t\treturn refs;\n \n-\tif (wt->id)\n-\t\trefs = ref_store_init(the_repository,\n-\t\t\t\t      git_common_path(\"worktrees/%s\", wt->id),\n+\tif (wt->id) {\n+\t\tstruct strbuf common_path = STRBUF_INIT;\n+\t\tstrbuf_git_common_path(&common_path, wt->repo,\n+\t\t\t\t      \"worktrees/%s\", wt->id);\n+\t\trefs = ref_store_init(wt->repo, common_path.buf,\n \t\t\t\t      REF_STORE_ALL_CAPS);\n-\telse\n-\t\trefs = ref_store_init(the_repository,\n-\t\t\t\t      get_git_common_dir(),\n+\t\tstrbuf_release(&common_path);\n+\t} else {\n+\t\trefs = ref_store_init(wt->repo, wt->repo->commondir,\n \t\t\t\t      REF_STORE_ALL_CAPS);\n+\t}\n \n \tif (refs)\n-\t\tregister_ref_store_map(&worktree_ref_stores, \"worktree\",\n-\t\t\t\t       refs, id);\n+\t\tregister_ref_store_map(&wt->repo->worktree_ref_stores,\n+\t\t\t\t       \"worktree\", refs, id);\n+\n \treturn refs;\n }\n \ndiff --git a/repository.c b/repository.c\nindex bb9b9e2b52..d29b0304fb 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -337,6 +337,10 @@ void repo_clear(struct repository *repo)\n \t\tref_store_release(e->value);\n \tstrmap_clear(&repo->submodule_ref_stores, 1);\n \n+\tstrmap_for_each_entry(&repo->worktree_ref_stores, &iter, e)\n+\t\tref_store_release(e->value);\n+\tstrmap_clear(&repo->worktree_ref_stores, 1);\n+\n \trepo_clear_path_cache(&repo->cached_paths);\n }\n \ndiff --git a/repository.h b/repository.h\nindex 0389df0461..4bd8969005 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -116,6 +116,12 @@ struct repository {\n \t */\n \tstruct strmap submodule_ref_stores;\n \n+\t/*\n+\t * A strmap of ref_stores, stored by worktree id, accessible via\n+\t * `get_worktree_ref_store()`.\n+\t */\n+\tstruct strmap worktree_ref_stores;\n+\n \t/*\n \t * Contains path to often used file names.\n \t */\ndiff --git a/worktree.c b/worktree.c\nindex cf5eea8c93..12eadacc61 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -65,6 +65,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)\n \tstrbuf_strip_suffix(&worktree_path, \"/.git\");\n \n \tCALLOC_ARRAY(worktree, 1);\n+\tworktree->repo = the_repository;\n \tworktree->path = strbuf_detach(&worktree_path, NULL);\n \t/*\n \t * NEEDSWORK: If this function is called from a secondary worktree and\n@@ -98,6 +99,7 @@ struct worktree *get_linked_worktree(const char *id,\n \tstrbuf_strip_suffix(&worktree_path, \"/.git\");\n \n \tCALLOC_ARRAY(worktree, 1);\n+\tworktree->repo = the_repository;\n \tworktree->path = strbuf_detach(&worktree_path, NULL);\n \tworktree->id = xstrdup(id);\n \tif (!skip_reading_head)\ndiff --git a/worktree.h b/worktree.h\nindex f14784a2ff..7cc6d90e66 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -6,6 +6,8 @@\n struct strbuf;\n \n struct worktree {\n+\t/* The repository this worktree belongs to. */\n+\tstruct repository *repo;\n \tchar *path;\n \tchar *id;\n \tchar *head_ref;\t\t/* NULL if HEAD is broken or detached */\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494948","messageId":"5306122d5806cf563cb6908480b78fcb12ba06c1.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 08/16] refs: convert iteration over replace refs to accept ref store","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:49Z","receivedAt":"2024-05-17T08:18:53Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The function `for_each_replace_ref()` is a bit of an oddball across the\nrefs interfaces as it accepts a pointer to the repository instead of a\npointer to the ref store. The only reason for us to accept a repository\nis so that we can eventually pass it back to the callback function that\nthe caller has provided. This is somewhat arbitrary though, as callers\nthat need the repository can instead make it accessible via the callback\npayload.\n\nRefactor the function to instead accept the ref store and adjust callers\naccordingly. This allows us to get rid of some of the boilerplate that\nwe had to carry to pass along the repository and brings us in line with\nthe other functions that iterate through refs.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/replace.c    | 13 ++++++----\n refs.c               | 58 ++++++--------------------------------------\n refs.h               | 17 ++-----------\n refs/iterator.c      |  6 ++---\n refs/refs-internal.h |  5 ++--\n replace-object.c     | 10 +++++---\n 6 files changed, 28 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex bc2a948c80..b09c78b77d 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -43,11 +43,12 @@ enum replace_format {\n };\n \n struct show_data {\n+\tstruct repository *repo;\n \tconst char *pattern;\n \tenum replace_format format;\n };\n \n-static int show_reference(struct repository *r, const char *refname,\n+static int show_reference(const char *refname,\n \t\t\t  const struct object_id *oid,\n \t\t\t  int flag UNUSED, void *cb_data)\n {\n@@ -62,11 +63,11 @@ static int show_reference(struct repository *r, const char *refname,\n \t\t\tstruct object_id object;\n \t\t\tenum object_type obj_type, repl_type;\n \n-\t\t\tif (repo_get_oid(r, refname, &object))\n+\t\t\tif (repo_get_oid(data->repo, refname, &object))\n \t\t\t\treturn error(_(\"failed to resolve '%s' as a valid ref\"), refname);\n \n-\t\t\tobj_type = oid_object_info(r, &object, NULL);\n-\t\t\trepl_type = oid_object_info(r, oid, NULL);\n+\t\t\tobj_type = oid_object_info(data->repo, &object, NULL);\n+\t\t\trepl_type = oid_object_info(data->repo, oid, NULL);\n \n \t\t\tprintf(\"%s (%s) -> %s (%s)\\n\", refname, type_name(obj_type),\n \t\t\t       oid_to_hex(oid), type_name(repl_type));\n@@ -80,6 +81,7 @@ static int list_replace_refs(const char *pattern, const char *format)\n {\n \tstruct show_data data;\n \n+\tdata.repo = the_repository;\n \tif (!pattern)\n \t\tpattern = \"*\";\n \tdata.pattern = pattern;\n@@ -99,7 +101,8 @@ static int list_replace_refs(const char *pattern, const char *format)\n \t\t\t       \"valid formats are 'short', 'medium' and 'long'\"),\n \t\t\t     format);\n \n-\tfor_each_replace_ref(the_repository, show_reference, (void *)&data);\n+\trefs_for_each_replace_ref(get_main_ref_store(the_repository),\n+\t\t\t\t  show_reference, (void *)&data);\n \n \treturn 0;\n }\ndiff --git a/refs.c b/refs.c\nindex 70e712fcef..d705add3b8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1576,53 +1576,12 @@ struct ref_iterator *refs_ref_iterator_begin(\n \treturn iter;\n }\n \n-/*\n- * Call fn for each reference in the specified submodule for which the\n- * refname begins with prefix. If trim is non-zero, then trim that\n- * many characters off the beginning of each refname before passing\n- * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to\n- * include broken references in the iteration. If fn ever returns a\n- * non-zero value, stop the iteration and return that value;\n- * otherwise, return 0.\n- */\n-static int do_for_each_repo_ref(struct repository *r, const char *prefix,\n-\t\t\t\teach_repo_ref_fn fn, int trim, int flags,\n-\t\t\t\tvoid *cb_data)\n-{\n-\tstruct ref_iterator *iter;\n-\tstruct ref_store *refs = get_main_ref_store(r);\n-\n-\tif (!refs)\n-\t\treturn 0;\n-\n-\titer = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);\n-\n-\treturn do_for_each_repo_ref_iterator(r, iter, fn, cb_data);\n-}\n-\n-struct do_for_each_ref_help {\n-\teach_ref_fn *fn;\n-\tvoid *cb_data;\n-};\n-\n-static int do_for_each_ref_helper(struct repository *r UNUSED,\n-\t\t\t\t  const char *refname,\n-\t\t\t\t  const struct object_id *oid,\n-\t\t\t\t  int flags,\n-\t\t\t\t  void *cb_data)\n-{\n-\tstruct do_for_each_ref_help *hp = cb_data;\n-\n-\treturn hp->fn(refname, oid, flags, hp->cb_data);\n-}\n-\n static int do_for_each_ref(struct ref_store *refs, const char *prefix,\n \t\t\t   const char **exclude_patterns,\n \t\t\t   each_ref_fn fn, int trim,\n \t\t\t   enum do_for_each_ref_flags flags, void *cb_data)\n {\n \tstruct ref_iterator *iter;\n-\tstruct do_for_each_ref_help hp = { fn, cb_data };\n \n \tif (!refs)\n \t\treturn 0;\n@@ -1630,8 +1589,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,\n \titer = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,\n \t\t\t\t       flags);\n \n-\treturn do_for_each_repo_ref_iterator(the_repository, iter,\n-\t\t\t\t\tdo_for_each_ref_helper, &hp);\n+\treturn do_for_each_ref_iterator(iter, fn, cb_data);\n }\n \n int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n@@ -1652,12 +1610,12 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,\n \treturn do_for_each_ref(refs, prefix, exclude_patterns, fn, 0, 0, cb_data);\n }\n \n-int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)\n+int refs_for_each_replace_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \tconst char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;\n-\treturn do_for_each_repo_ref(r, git_replace_ref_base, fn,\n-\t\t\t\t    strlen(git_replace_ref_base),\n-\t\t\t\t    DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n+\treturn do_for_each_ref(refs, git_replace_ref_base, NULL, fn,\n+\t\t\t       strlen(git_replace_ref_base),\n+\t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n }\n \n int refs_for_each_namespaced_ref(struct ref_store *refs,\n@@ -2425,8 +2383,7 @@ struct do_for_each_reflog_help {\n \tvoid *cb_data;\n };\n \n-static int do_for_each_reflog_helper(struct repository *r UNUSED,\n-\t\t\t\t     const char *refname,\n+static int do_for_each_reflog_helper(const char *refname,\n \t\t\t\t     const struct object_id *oid UNUSED,\n \t\t\t\t     int flags,\n \t\t\t\t     void *cb_data)\n@@ -2442,8 +2399,7 @@ int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_dat\n \n \titer = refs->be->reflog_iterator_begin(refs);\n \n-\treturn do_for_each_repo_ref_iterator(the_repository, iter,\n-\t\t\t\t\t     do_for_each_reflog_helper, &hp);\n+\treturn do_for_each_ref_iterator(iter, do_for_each_reflog_helper, &hp);\n }\n \n int refs_for_each_reflog_ent_reverse(struct ref_store *refs,\ndiff --git a/refs.h b/refs.h\nindex 90a7e2dde3..fa1f19464e 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -298,16 +298,6 @@ struct ref_transaction;\n typedef int each_ref_fn(const char *refname,\n \t\t\tconst struct object_id *oid, int flags, void *cb_data);\n \n-/*\n- * The same as each_ref_fn, but also with a repository argument that\n- * contains the repository associated with the callback.\n- */\n-typedef int each_repo_ref_fn(struct repository *r,\n-\t\t\t     const char *refname,\n-\t\t\t     const struct object_id *oid,\n-\t\t\t     int flags,\n-\t\t\t     void *cb_data);\n-\n /*\n  * The following functions invoke the specified callback function for\n  * each reference indicated.  If the function ever returns a nonzero\n@@ -329,6 +319,8 @@ int refs_for_each_branch_ref(struct ref_store *refs,\n \t\t\t     each_ref_fn fn, void *cb_data);\n int refs_for_each_remote_ref(struct ref_store *refs,\n \t\t\t     each_ref_fn fn, void *cb_data);\n+int refs_for_each_replace_ref(struct ref_store *refs,\n+\t\t\t      each_ref_fn fn, void *cb_data);\n \n /*\n  * references matching any pattern in \"exclude_patterns\" are omitted from the\n@@ -353,11 +345,6 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *refs,\n \t\t\t\t      const char **exclude_patterns,\n \t\t\t\t      each_ref_fn fn, void *cb_data);\n \n-/**\n- * iterate refs from the respective area.\n- */\n-int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);\n-\n /* iterates all refs that match the specified glob pattern. */\n int refs_for_each_glob_ref(struct ref_store *refs, each_ref_fn fn,\n \t\t\t   const char *pattern, void *cb_data);\ndiff --git a/refs/iterator.c b/refs/iterator.c\nindex 9db8b056d5..d355ebf0d5 100644\n--- a/refs/iterator.c\n+++ b/refs/iterator.c\n@@ -440,15 +440,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,\n \n struct ref_iterator *current_ref_iter = NULL;\n \n-int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,\n-\t\t\t\t  each_repo_ref_fn fn, void *cb_data)\n+int do_for_each_ref_iterator(struct ref_iterator *iter,\n+\t\t\t     each_ref_fn fn, void *cb_data)\n {\n \tint retval = 0, ok;\n \tstruct ref_iterator *old_ref_iter = current_ref_iter;\n \n \tcurrent_ref_iter = iter;\n \twhile ((ok = ref_iterator_advance(iter)) == ITER_OK) {\n-\t\tretval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);\n+\t\tretval = fn(iter->refname, iter->oid, iter->flags, cb_data);\n \t\tif (retval) {\n \t\t\t/*\n \t\t\t * If ref_iterator_abort() returns ITER_ERROR,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 178a355eb0..07e24c8481 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -503,9 +503,8 @@ extern struct ref_iterator *current_ref_iter;\n  * adapter between the callback style of reference iteration and the\n  * iterator style.\n  */\n-int do_for_each_repo_ref_iterator(struct repository *r,\n-\t\t\t\t  struct ref_iterator *iter,\n-\t\t\t\t  each_repo_ref_fn fn, void *cb_data);\n+int do_for_each_ref_iterator(struct ref_iterator *iter,\n+\t\t\t     each_ref_fn fn, void *cb_data);\n \n struct ref_store;\n \ndiff --git a/replace-object.c b/replace-object.c\nindex 523215589d..73f5acbcd9 100644\n--- a/replace-object.c\n+++ b/replace-object.c\n@@ -8,12 +8,13 @@\n #include \"repository.h\"\n #include \"commit.h\"\n \n-static int register_replace_ref(struct repository *r,\n-\t\t\t\tconst char *refname,\n+static int register_replace_ref(const char *refname,\n \t\t\t\tconst struct object_id *oid,\n \t\t\t\tint flag UNUSED,\n-\t\t\t\tvoid *cb_data UNUSED)\n+\t\t\t\tvoid *cb_data)\n {\n+\tstruct repository *r = cb_data;\n+\n \t/* Get sha1 from refname */\n \tconst char *slash = strrchr(refname, '/');\n \tconst char *hash = slash ? slash + 1 : refname;\n@@ -50,7 +51,8 @@ void prepare_replace_object(struct repository *r)\n \t\txmalloc(sizeof(*r->objects->replace_map));\n \toidmap_init(r->objects->replace_map, 0);\n \n-\tfor_each_replace_ref(r, register_replace_ref, NULL);\n+\trefs_for_each_replace_ref(get_main_ref_store(r),\n+\t\t\t\t  register_replace_ref, r);\n \tr->objects->replace_map_initialized = 1;\n \n \tpthread_mutex_unlock(&r->objects->replace_mutex);\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494949","messageId":"423d7b3fb65067fe381b6654e74f28da83e470bc.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 09/16] refs: pass ref store when detecting dangling symrefs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:53Z","receivedAt":"2024-05-17T08:18:58Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Both `warn_dangling_symref()` and `warn_dangling_symrefs()` derive the\nref store via `the_repository`. Adapt them to instead take in the ref\nstore as a parameter. While at it, rename the functions to have a `ref_`\nprefix to align them with other functions that take a ref store.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/fetch.c  |  3 ++-\n builtin/remote.c |  3 ++-\n refs.c           | 40 ++++++++++++++++++++--------------------\n refs.h           |  7 ++++---\n 4 files changed, 28 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 3829d66b40..3df1c0c052 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1412,7 +1412,8 @@ static int prune_refs(struct display_state *display_state,\n \t\t\t\t\t   _(\"(none)\"), ref->name,\n \t\t\t\t\t   &ref->new_oid, &ref->old_oid,\n \t\t\t\t\t   summary_width);\n-\t\t\twarn_dangling_symref(stderr, dangling_msg, ref->name);\n+\t\t\trefs_warn_dangling_symref(get_main_ref_store(the_repository),\n+\t\t\t\t\t\t  stderr, dangling_msg, ref->name);\n \t\t}\n \t}\n \ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex ff70d6835a..c0b513cc95 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -1477,7 +1477,8 @@ static int prune_remote(const char *remote, int dry_run)\n \t\t\t       abbrev_ref(refname, \"refs/remotes/\"));\n \t}\n \n-\twarn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);\n+\trefs_warn_dangling_symrefs(get_main_ref_store(the_repository),\n+\t\t\t\t   stdout, dangling_msg, &refs_to_prune);\n \n \tstring_list_clear(&refs_to_prune, 0);\n \tfree_remote_ref_states(&states);\ndiff --git a/refs.c b/refs.c\nindex d705add3b8..48323dd28d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -447,6 +447,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid\n }\n \n struct warn_if_dangling_data {\n+\tstruct ref_store *refs;\n \tFILE *fp;\n \tconst char *refname;\n \tconst struct string_list *refnames;\n@@ -463,8 +464,7 @@ static int warn_if_dangling_symref(const char *refname,\n \tif (!(flags & REF_ISSYMREF))\n \t\treturn 0;\n \n-\tresolves_to = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),\n-\t\t\t\t\t      refname, 0, NULL, NULL);\n+\tresolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);\n \tif (!resolves_to\n \t    || (d->refname\n \t\t? strcmp(resolves_to, d->refname)\n@@ -477,28 +477,28 @@ static int warn_if_dangling_symref(const char *refname,\n \treturn 0;\n }\n \n-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)\n+void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,\n+\t\t\t       const char *msg_fmt, const char *refname)\n {\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = refname;\n-\tdata.refnames = NULL;\n-\tdata.msg_fmt = msg_fmt;\n-\trefs_for_each_rawref(get_main_ref_store(the_repository),\n-\t\t\t     warn_if_dangling_symref, &data);\n+\tstruct warn_if_dangling_data data = {\n+\t\t.refs = refs,\n+\t\t.fp = fp,\n+\t\t.refname = refname,\n+\t\t.msg_fmt = msg_fmt,\n+\t};\n+\trefs_for_each_rawref(refs, warn_if_dangling_symref, &data);\n }\n \n-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)\n+void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,\n+\t\t\t\tconst char *msg_fmt, const struct string_list *refnames)\n {\n-\tstruct warn_if_dangling_data data;\n-\n-\tdata.fp = fp;\n-\tdata.refname = NULL;\n-\tdata.refnames = refnames;\n-\tdata.msg_fmt = msg_fmt;\n-\trefs_for_each_rawref(get_main_ref_store(the_repository),\n-\t\t\t     warn_if_dangling_symref, &data);\n+\tstruct warn_if_dangling_data data = {\n+\t\t.refs = refs,\n+\t\t.fp = fp,\n+\t\t.refnames = refnames,\n+\t\t.msg_fmt = msg_fmt,\n+\t};\n+\trefs_for_each_rawref(refs, warn_if_dangling_symref, &data);\n }\n \n int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\ndiff --git a/refs.h b/refs.h\nindex fa1f19464e..56d9714293 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -388,9 +388,10 @@ static inline const char *has_glob_specials(const char *pattern)\n \treturn strpbrk(pattern, \"?*[\");\n }\n \n-void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);\n-void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,\n-\t\t\t   const struct string_list *refnames);\n+void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,\n+\t\t\t       const char *msg_fmt, const char *refname);\n+void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,\n+\t\t\t\tconst char *msg_fmt, const struct string_list *refnames);\n \n /*\n  * Flags for controlling behaviour of pack_refs()\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494950","messageId":"3c6f814158bd9f6ab78362181614f3e2112e4a19.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 10/16] refs: move object peeling into \"object.c\"","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:18:59Z","receivedAt":"2024-05-17T08:19:03Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Peeling an object has nothing to do with refs, but we still have the\ncode in \"refs.c\". Move it over into \"object.c\", which is a more natural\nplace to put it.\n\nIdeally, we'd also move `peel_iterated_oid()` over into \"object.c\". But\nthis function is tied to the refs interfaces because it uses a global\nref iterator variable to optimize peeling when the iterator already has\nthe peeled object ID readily available.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n object.c             | 21 +++++++++++++++++++++\n object.h             | 34 ++++++++++++++++++++++++++++++++++\n refs.c               | 22 ----------------------\n refs/refs-internal.h | 34 ----------------------------------\n 4 files changed, 55 insertions(+), 56 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 51e384828e..995041926a 100644\n--- a/object.c\n+++ b/object.c\n@@ -207,6 +207,27 @@ struct object *lookup_object_by_type(struct repository *r,\n \t}\n }\n \n+enum peel_status peel_object(const struct object_id *name, struct object_id *oid)\n+{\n+\tstruct object *o = lookup_unknown_object(the_repository, name);\n+\n+\tif (o->type == OBJ_NONE) {\n+\t\tint type = oid_object_info(the_repository, name, NULL);\n+\t\tif (type < 0 || !object_as_type(o, type, 0))\n+\t\t\treturn PEEL_INVALID;\n+\t}\n+\n+\tif (o->type != OBJ_TAG)\n+\t\treturn PEEL_NON_TAG;\n+\n+\to = deref_tag_noverify(o);\n+\tif (!o)\n+\t\treturn PEEL_INVALID;\n+\n+\toidcpy(oid, &o->oid);\n+\treturn PEEL_PEELED;\n+}\n+\n struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)\n {\n \tstruct object *obj;\ndiff --git a/object.h b/object.h\nindex 9293e703cc..31ccd1bb10 100644\n--- a/object.h\n+++ b/object.h\n@@ -256,6 +256,40 @@ struct object *lookup_unknown_object(struct repository *r, const struct object_i\n struct object *lookup_object_by_type(struct repository *r, const struct object_id *oid,\n \t\t\t\t     enum object_type type);\n \n+enum peel_status {\n+\t/* object was peeled successfully: */\n+\tPEEL_PEELED = 0,\n+\n+\t/*\n+\t * object cannot be peeled because the named object (or an\n+\t * object referred to by a tag in the peel chain), does not\n+\t * exist.\n+\t */\n+\tPEEL_INVALID = -1,\n+\n+\t/* object cannot be peeled because it is not a tag: */\n+\tPEEL_NON_TAG = -2,\n+\n+\t/* ref_entry contains no peeled value because it is a symref: */\n+\tPEEL_IS_SYMREF = -3,\n+\n+\t/*\n+\t * ref_entry cannot be peeled because it is broken (i.e., the\n+\t * symbolic reference cannot even be resolved to an object\n+\t * name):\n+\t */\n+\tPEEL_BROKEN = -4\n+};\n+\n+/*\n+ * Peel the named object; i.e., if the object is a tag, resolve the\n+ * tag recursively until a non-tag is found.  If successful, store the\n+ * result to oid and return PEEL_PEELED.  If the object is not a tag\n+ * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n+ * and leave oid unchanged.\n+ */\n+enum peel_status peel_object(const struct object_id *name, struct object_id *oid);\n+\n struct object_list *object_list_insert(struct object *item,\n \t\t\t\t       struct object_list **list_p);\n \ndiff --git a/refs.c b/refs.c\nindex 48323dd28d..d1b530679f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -19,7 +19,6 @@\n #include \"object-store-ll.h\"\n #include \"object.h\"\n #include \"path.h\"\n-#include \"tag.h\"\n #include \"submodule.h\"\n #include \"worktree.h\"\n #include \"strvec.h\"\n@@ -425,27 +424,6 @@ static int for_each_filter_refs(const char *refname,\n \treturn filter->fn(refname, oid, flags, filter->cb_data);\n }\n \n-enum peel_status peel_object(const struct object_id *name, struct object_id *oid)\n-{\n-\tstruct object *o = lookup_unknown_object(the_repository, name);\n-\n-\tif (o->type == OBJ_NONE) {\n-\t\tint type = oid_object_info(the_repository, name, NULL);\n-\t\tif (type < 0 || !object_as_type(o, type, 0))\n-\t\t\treturn PEEL_INVALID;\n-\t}\n-\n-\tif (o->type != OBJ_TAG)\n-\t\treturn PEEL_NON_TAG;\n-\n-\to = deref_tag_noverify(o);\n-\tif (!o)\n-\t\treturn PEEL_INVALID;\n-\n-\toidcpy(oid, &o->oid);\n-\treturn PEEL_PEELED;\n-}\n-\n struct warn_if_dangling_data {\n \tstruct ref_store *refs;\n \tFILE *fp;\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 07e24c8481..8d85589081 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -69,40 +69,6 @@ int ref_resolves_to_object(const char *refname,\n \t\t\t   const struct object_id *oid,\n \t\t\t   unsigned int flags);\n \n-enum peel_status {\n-\t/* object was peeled successfully: */\n-\tPEEL_PEELED = 0,\n-\n-\t/*\n-\t * object cannot be peeled because the named object (or an\n-\t * object referred to by a tag in the peel chain), does not\n-\t * exist.\n-\t */\n-\tPEEL_INVALID = -1,\n-\n-\t/* object cannot be peeled because it is not a tag: */\n-\tPEEL_NON_TAG = -2,\n-\n-\t/* ref_entry contains no peeled value because it is a symref: */\n-\tPEEL_IS_SYMREF = -3,\n-\n-\t/*\n-\t * ref_entry cannot be peeled because it is broken (i.e., the\n-\t * symbolic reference cannot even be resolved to an object\n-\t * name):\n-\t */\n-\tPEEL_BROKEN = -4\n-};\n-\n-/*\n- * Peel the named object; i.e., if the object is a tag, resolve the\n- * tag recursively until a non-tag is found.  If successful, store the\n- * result to oid and return PEEL_PEELED.  If the object is not a tag\n- * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n- * and leave oid unchanged.\n- */\n-enum peel_status peel_object(const struct object_id *name, struct object_id *oid);\n-\n /**\n  * Information needed for a single ref update. Set new_oid to the new\n  * value or to null_oid to delete the ref. To check the old value\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494951","messageId":"272cd49357b33e4df9a53fd76ee1011b840570fb.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 11/16] refs: pass repo when peeling objects","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:04Z","receivedAt":"2024-05-17T08:19:08Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Both `peel_object()` and `peel_iterated_oid()` implicitly rely on\n`the_repository` to look up objects. Despite the fact that we want to\nget rid of `the_repository`, it also leads to some restrictions in our\nref iterators when trying to retrieve the peeled value for a repository\nother than `the_repository`.\n\nRefactor these functions such that both take a repository as argument\nand remove the now-unnecessary restrictions.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/describe.c      |  2 +-\n builtin/gc.c            |  2 +-\n builtin/pack-objects.c  |  6 +++---\n builtin/repack.c        |  2 +-\n builtin/show-ref.c      |  2 +-\n commit-graph.c          |  2 +-\n ls-refs.c               |  2 +-\n midx-write.c            |  2 +-\n object.c                | 10 ++++++----\n object.h                |  3 ++-\n ref-filter.c            |  2 +-\n refs.c                  |  4 ++--\n refs.h                  |  5 +++--\n refs/packed-backend.c   |  8 +++-----\n refs/ref-cache.c        |  5 +----\n refs/reftable-backend.c |  6 ++++--\n t/helper/test-reach.c   |  2 +-\n tag.c                   |  4 ++--\n tag.h                   |  2 +-\n upload-pack.c           |  2 +-\n 20 files changed, 37 insertions(+), 36 deletions(-)\n\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 82aca00c80..e5287eddf2 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -200,7 +200,7 @@ static int get_name(const char *path, const struct object_id *oid,\n \t}\n \n \t/* Is it annotated? */\n-\tif (!peel_iterated_oid(oid, &peeled)) {\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled)) {\n \t\tis_annotated = !oideq(oid, &peeled);\n \t} else {\n \t\toidcpy(&peeled, oid);\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 054fca7835..72bac2554f 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -846,7 +846,7 @@ static int dfs_on_ref(const char *refname UNUSED,\n \tstruct commit_list *stack = NULL;\n \tstruct commit *commit;\n \n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\toid = &peeled;\n \tif (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex cd2396896d..62ddf41f84 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -779,7 +779,7 @@ static int mark_tagged(const char *path UNUSED, const struct object_id *oid,\n \n \tif (entry)\n \t\tentry->tagged = 1;\n-\tif (!peel_iterated_oid(oid, &peeled)) {\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled)) {\n \t\tentry = packlist_find(&to_pack, &peeled);\n \t\tif (entry)\n \t\t\tentry->tagged = 1;\n@@ -3125,7 +3125,7 @@ static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,\n {\n \tstruct object_id peeled;\n \n-\tif (!peel_iterated_oid(oid, &peeled) && obj_is_packed(&peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))\n \t\tadd_tag_chain(oid);\n \treturn 0;\n }\n@@ -4074,7 +4074,7 @@ static int mark_bitmap_preferred_tip(const char *refname,\n \tstruct object_id peeled;\n \tstruct object *object;\n \n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\toid = &peeled;\n \n \tobject = parse_object_or_die(oid, refname);\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 43491a4cbf..58ad82dd97 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -673,7 +673,7 @@ static int midx_snapshot_ref_one(const char *refname UNUSED,\n \tstruct midx_snapshot_ref_data *data = _data;\n \tstruct object_id peeled;\n \n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\toid = &peeled;\n \n \tif (oidset_insert(&data->seen, oid))\ndiff --git a/builtin/show-ref.c b/builtin/show-ref.c\nindex 151ef35134..3114bdc391 100644\n--- a/builtin/show-ref.c\n+++ b/builtin/show-ref.c\n@@ -50,7 +50,7 @@ static void show_one(const struct show_one_options *opts,\n \tif (!opts->deref_tags)\n \t\treturn;\n \n-\tif (!peel_iterated_oid(oid, &peeled)) {\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled)) {\n \t\thex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);\n \t\tprintf(\"%s %s^{}\\n\", hex, refname);\n \t}\ndiff --git a/commit-graph.c b/commit-graph.c\nindex c4c156ff52..e5dd3553df 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1821,7 +1821,7 @@ static int add_ref_to_set(const char *refname UNUSED,\n \tstruct object_id peeled;\n \tstruct refs_cb_data *data = (struct refs_cb_data *)cb_data;\n \n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\toid = &peeled;\n \tif (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)\n \t\toidset_insert(data->commits, oid);\ndiff --git a/ls-refs.c b/ls-refs.c\nindex 8e3ffff811..398afe4ce3 100644\n--- a/ls-refs.c\n+++ b/ls-refs.c\n@@ -110,7 +110,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \n \tif (data->peel && oid) {\n \t\tstruct object_id peeled;\n-\t\tif (!peel_iterated_oid(oid, &peeled))\n+\t\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\t\tstrbuf_addf(&data->buf, \" peeled:%s\", oid_to_hex(&peeled));\n \t}\n \ndiff --git a/midx-write.c b/midx-write.c\nindex 9d096d5a28..86173abdb9 100644\n--- a/midx-write.c\n+++ b/midx-write.c\n@@ -664,7 +664,7 @@ static int add_ref_to_pending(const char *refname,\n \t\treturn 0;\n \t}\n \n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\toid = &peeled;\n \n \tobject = parse_object_or_die(oid, refname);\ndiff --git a/object.c b/object.c\nindex 995041926a..93b5d97fdb 100644\n--- a/object.c\n+++ b/object.c\n@@ -207,12 +207,14 @@ struct object *lookup_object_by_type(struct repository *r,\n \t}\n }\n \n-enum peel_status peel_object(const struct object_id *name, struct object_id *oid)\n+enum peel_status peel_object(struct repository *r,\n+\t\t\t     const struct object_id *name,\n+\t\t\t     struct object_id *oid)\n {\n-\tstruct object *o = lookup_unknown_object(the_repository, name);\n+\tstruct object *o = lookup_unknown_object(r, name);\n \n \tif (o->type == OBJ_NONE) {\n-\t\tint type = oid_object_info(the_repository, name, NULL);\n+\t\tint type = oid_object_info(r, name, NULL);\n \t\tif (type < 0 || !object_as_type(o, type, 0))\n \t\t\treturn PEEL_INVALID;\n \t}\n@@ -220,7 +222,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid\n \tif (o->type != OBJ_TAG)\n \t\treturn PEEL_NON_TAG;\n \n-\to = deref_tag_noverify(o);\n+\to = deref_tag_noverify(r, o);\n \tif (!o)\n \t\treturn PEEL_INVALID;\n \ndiff --git a/object.h b/object.h\nindex 31ccd1bb10..83fcc035e9 100644\n--- a/object.h\n+++ b/object.h\n@@ -288,7 +288,8 @@ enum peel_status {\n  * or is not valid, return PEEL_NON_TAG or PEEL_INVALID, respectively,\n  * and leave oid unchanged.\n  */\n-enum peel_status peel_object(const struct object_id *name, struct object_id *oid);\n+enum peel_status peel_object(struct repository *r,\n+\t\t\t     const struct object_id *name, struct object_id *oid);\n \n struct object_list *object_list_insert(struct object *item,\n \t\t\t\t       struct object_list **list_p);\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 31cc096644..79e7d3910d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2520,7 +2520,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t * If it is a tag object, see if we use the peeled value. If we do,\n \t * grab the peeled OID.\n \t */\n-\tif (need_tagged && peel_iterated_oid(&obj->oid, &oi_deref.oid))\n+\tif (need_tagged && peel_iterated_oid(the_repository, &obj->oid, &oi_deref.oid))\n \t\tdie(\"bad tag\");\n \n \treturn get_object(ref, 1, &obj, &oi_deref, err);\ndiff --git a/refs.c b/refs.c\nindex d1b530679f..5f1819b33e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2064,14 +2064,14 @@ int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)\n \treturn refs->be->pack_refs(refs, opts);\n }\n \n-int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)\n+int peel_iterated_oid(struct repository *r, const struct object_id *base, struct object_id *peeled)\n {\n \tif (current_ref_iter &&\n \t    (current_ref_iter->oid == base ||\n \t     oideq(current_ref_iter->oid, base)))\n \t\treturn ref_iterator_peel(current_ref_iter, peeled);\n \n-\treturn peel_object(base, peeled) ? -1 : 0;\n+\treturn peel_object(r, base, peeled) ? -1 : 0;\n }\n \n int refs_create_symref(struct ref_store *refs,\ndiff --git a/refs.h b/refs.h\nindex 56d9714293..e043b6cfa3 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -127,13 +127,14 @@ void ref_store_release(struct ref_store *ref_store);\n  * Return the peeled value of the oid currently being iterated via\n  * for_each_ref(), etc. This is equivalent to calling:\n  *\n- *   peel_object(oid, &peeled);\n+ *   peel_object(r, oid, &peeled);\n  *\n  * with the \"oid\" value given to the each_ref_fn callback, except\n  * that some ref storage may be able to answer the query without\n  * actually loading the object in memory.\n  */\n-int peel_iterated_oid(const struct object_id *base, struct object_id *peeled);\n+int peel_iterated_oid(struct repository *r,\n+\t\t      const struct object_id *base, struct object_id *peeled);\n \n /**\n  * Resolve refname in the nested \"gitlink\" repository in the specified\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex 9c98e6295f..dfdd718eb9 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -953,16 +953,13 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,\n \tstruct packed_ref_iterator *iter =\n \t\t(struct packed_ref_iterator *)ref_iterator;\n \n-\tif (iter->repo != the_repository)\n-\t\tBUG(\"peeling for non-the_repository is not supported\");\n-\n \tif ((iter->base.flags & REF_KNOWS_PEELED)) {\n \t\toidcpy(peeled, &iter->peeled);\n \t\treturn is_null_oid(&iter->peeled) ? -1 : 0;\n \t} else if ((iter->base.flags & (REF_ISBROKEN | REF_ISSYMREF))) {\n \t\treturn -1;\n \t} else {\n-\t\treturn peel_object(&iter->oid, peeled) ? -1 : 0;\n+\t\treturn peel_object(iter->repo, &iter->oid, peeled) ? -1 : 0;\n \t}\n }\n \n@@ -1421,7 +1418,8 @@ static int write_with_updates(struct packed_ref_store *refs,\n \t\t\ti++;\n \t\t} else {\n \t\t\tstruct object_id peeled;\n-\t\t\tint peel_error = peel_object(&update->new_oid,\n+\t\t\tint peel_error = peel_object(refs->base.repo,\n+\t\t\t\t\t\t     &update->new_oid,\n \t\t\t\t\t\t     &peeled);\n \n \t\t\tif (write_packed_entry(out, update->refname,\ndiff --git a/refs/ref-cache.c b/refs/ref-cache.c\nindex 9f9797209a..b6c53fc8ed 100644\n--- a/refs/ref-cache.c\n+++ b/refs/ref-cache.c\n@@ -441,10 +441,7 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,\n {\n \tstruct cache_ref_iterator *iter =\n \t\t(struct cache_ref_iterator *)ref_iterator;\n-\n-\tif (iter->repo != the_repository)\n-\t\tBUG(\"peeling for non-the_repository is not supported\");\n-\treturn peel_object(ref_iterator->oid, peeled) ? -1 : 0;\n+\treturn peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;\n }\n \n static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)\ndiff --git a/refs/reftable-backend.c b/refs/reftable-backend.c\nindex 7b73f73f59..850466da4b 100644\n--- a/refs/reftable-backend.c\n+++ b/refs/reftable-backend.c\n@@ -1144,7 +1144,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data\n \t\t\tref.refname = (char *)u->refname;\n \t\t\tref.update_index = ts;\n \n-\t\t\tpeel_error = peel_object(&u->new_oid, &peeled);\n+\t\t\tpeel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled);\n \t\t\tif (!peel_error) {\n \t\t\t\tref.value_type = REFTABLE_REF_VAL2;\n \t\t\t\tmemcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);\n@@ -2045,6 +2045,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,\n }\n \n struct reflog_expiry_arg {\n+\tstruct reftable_ref_store *refs;\n \tstruct reftable_stack *stack;\n \tstruct reftable_log_record *records;\n \tstruct object_id update_oid;\n@@ -2073,7 +2074,7 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da\n \t\tref.refname = (char *)arg->refname;\n \t\tref.update_index = ts;\n \n-\t\tif (!peel_object(&arg->update_oid, &peeled)) {\n+\t\tif (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled)) {\n \t\t\tref.value_type = REFTABLE_REF_VAL2;\n \t\t\tmemcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);\n \t\t\tmemcpy(ref.value.val2.value, arg->update_oid.hash, GIT_MAX_RAWSZ);\n@@ -2235,6 +2236,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,\n \t    reftable_ref_record_val1(&ref_record))\n \t\toidread(&arg.update_oid, last_hash);\n \n+\targ.refs = refs;\n \targ.records = rewritten;\n \targ.len = logs_nr;\n \targ.stack = stack,\ndiff --git a/t/helper/test-reach.c b/t/helper/test-reach.c\nindex 1e3b431e3e..1ba226f1f9 100644\n--- a/t/helper/test-reach.c\n+++ b/t/helper/test-reach.c\n@@ -62,7 +62,7 @@ int cmd__reach(int ac, const char **av)\n \t\t\tdie(\"failed to resolve %s\", buf.buf + 2);\n \n \t\torig = parse_object(r, &oid);\n-\t\tpeeled = deref_tag_noverify(orig);\n+\t\tpeeled = deref_tag_noverify(the_repository, orig);\n \n \t\tif (!peeled)\n \t\t\tdie(\"failed to load commit for input %s resulting in oid %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex fc3834db46..52bbe50819 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -91,10 +91,10 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war\n \treturn o;\n }\n \n-struct object *deref_tag_noverify(struct object *o)\n+struct object *deref_tag_noverify(struct repository *r, struct object *o)\n {\n \twhile (o && o->type == OBJ_TAG) {\n-\t\to = parse_object(the_repository, &o->oid);\n+\t\to = parse_object(r, &o->oid);\n \t\tif (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)\n \t\t\to = ((struct tag *)o)->tagged;\n \t\telse\ndiff --git a/tag.h b/tag.h\nindex 3ce8e72192..c49d7c19ad 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -16,7 +16,7 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u\n int parse_tag(struct tag *item);\n void release_tag_memory(struct tag *t);\n struct object *deref_tag(struct repository *r, struct object *, const char *, int);\n-struct object *deref_tag_noverify(struct object *);\n+struct object *deref_tag_noverify(struct repository *r, struct object *);\n int gpg_verify_tag(const struct object_id *oid,\n \t\t   const char *name_to_report, unsigned flags);\n struct object_id *get_tagged_oid(struct tag *tag);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 8fbd138515..bbfb04c8bd 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1269,7 +1269,7 @@ static void write_v0_ref(struct upload_pack_data *data,\n \t\tpacket_fwrite_fmt(stdout, \"%s %s\\n\", oid_to_hex(oid), refname_nons);\n \t}\n \tcapabilities = NULL;\n-\tif (!peel_iterated_oid(oid, &peeled))\n+\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n \t\tpacket_fwrite_fmt(stdout, \"%s %s^{}\\n\", oid_to_hex(&peeled), refname_nons);\n \treturn;\n }\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494953","messageId":"e02e76701f94a062337a303e90bf276fc9a5a0b9.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 12/16] refs: drop `git_default_branch_name()`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:09Z","receivedAt":"2024-05-17T08:19:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The `git_default_branch_name()` function is a thin wrapper around\n`repo_default_branch_name()` with two differences:\n\n  - We implicitly rely on `the_repository`.\n\n  - We cache the default branch name.\n\nNone of the callsites of `git_default_branch_name()` are hot code paths\nthough, so the caching of the branch name is not really required.\n\nRefactor the callsites to use `repo_default_branch_name()` instead and\ndrop `git_default_branch_name()`, thus getting rid of one more case\nwhere we rely on `the_repository`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/clone.c |  5 ++++-\n builtin/var.c   |  2 +-\n refs.c          | 10 ----------\n refs.h          |  4 +---\n remote.c        | 12 ++++++++----\n setup.c         |  5 ++++-\n 6 files changed, 18 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 554b29768c..bd3e8302ed 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -1468,6 +1468,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t} else if (remote_head) {\n \t\tour_head_points_at = NULL;\n \t} else {\n+\t\tchar *to_free = NULL;\n \t\tconst char *branch;\n \n \t\tif (!mapped_refs) {\n@@ -1480,7 +1481,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\t\t\t\"refs/heads/\", &branch)) {\n \t\t\tunborn_head  = xstrdup(transport_ls_refs_options.unborn_head_target);\n \t\t} else {\n-\t\t\tbranch = git_default_branch_name(0);\n+\t\t\tbranch = to_free = repo_default_branch_name(the_repository, 0);\n \t\t\tunborn_head = xstrfmt(\"refs/heads/%s\", branch);\n \t\t}\n \n@@ -1496,6 +1497,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\t * a match.\n \t\t */\n \t\tour_head_points_at = find_remote_branch(mapped_refs, branch);\n+\n+\t\tfree(to_free);\n \t}\n \n \twrite_refspec_config(src_ref_prefix, our_head_points_at,\ndiff --git a/builtin/var.c b/builtin/var.c\nindex cf5567208a..5dc384810c 100644\n--- a/builtin/var.c\n+++ b/builtin/var.c\n@@ -46,7 +46,7 @@ static char *pager(int ident_flag UNUSED)\n \n static char *default_branch(int ident_flag UNUSED)\n {\n-\treturn xstrdup_or_null(git_default_branch_name(1));\n+\treturn repo_default_branch_name(the_repository, 1);\n }\n \n static char *shell_path(int ident_flag UNUSED)\ndiff --git a/refs.c b/refs.c\nindex 5f1819b33e..83cd965a26 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -664,16 +664,6 @@ char *repo_default_branch_name(struct repository *r, int quiet)\n \treturn ret;\n }\n \n-const char *git_default_branch_name(int quiet)\n-{\n-\tstatic char *ret;\n-\n-\tif (!ret)\n-\t\tret = repo_default_branch_name(the_repository, quiet);\n-\n-\treturn ret;\n-}\n-\n /*\n  * *string and *len will only be substituted, and *string returned (for\n  * later free()ing) if the string passed in is a magic short-hand form\ndiff --git a/refs.h b/refs.h\nindex e043b6cfa3..e906dbb44a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -169,10 +169,8 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **ref);\n /*\n  * Retrieves the default branch name for newly-initialized repositories.\n  *\n- * The return value of `repo_default_branch_name()` is an allocated string. The\n- * return value of `git_default_branch_name()` is a singleton.\n+ * The return value is an allocated string.\n  */\n-const char *git_default_branch_name(int quiet);\n char *repo_default_branch_name(struct repository *r, int quiet);\n \n /*\ndiff --git a/remote.c b/remote.c\nindex ec8c158e60..85c390b199 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -305,7 +305,7 @@ static void read_remotes_file(struct remote_state *remote_state,\n static void read_branches_file(struct remote_state *remote_state,\n \t\t\t       struct remote *remote)\n {\n-\tchar *frag;\n+\tchar *frag, *to_free = NULL;\n \tstruct strbuf buf = STRBUF_INIT;\n \tFILE *f = fopen_or_warn(git_path(\"branches/%s\", remote->name), \"r\");\n \n@@ -333,7 +333,7 @@ static void read_branches_file(struct remote_state *remote_state,\n \tif (frag)\n \t\t*(frag++) = '\\0';\n \telse\n-\t\tfrag = (char *)git_default_branch_name(0);\n+\t\tfrag = to_free = repo_default_branch_name(the_repository, 0);\n \n \tadd_url_alias(remote_state, remote, strbuf_detach(&buf, NULL));\n \trefspec_appendf(&remote->fetch, \"refs/heads/%s:refs/heads/%s\",\n@@ -345,6 +345,8 @@ static void read_branches_file(struct remote_state *remote_state,\n \t */\n \trefspec_appendf(&remote->push, \"HEAD:refs/heads/%s\", frag);\n \tremote->fetch_tags = 1; /* always auto-follow */\n+\n+\tfree(to_free);\n }\n \n static int handle_config(const char *key, const char *value,\n@@ -2388,11 +2390,13 @@ struct ref *guess_remote_head(const struct ref *head,\n \n \t/* If a remote branch exists with the default branch name, let's use it. */\n \tif (!all) {\n-\t\tchar *ref = xstrfmt(\"refs/heads/%s\",\n-\t\t\t\t    git_default_branch_name(0));\n+\t\tchar *default_branch = repo_default_branch_name(the_repository, 0);\n+\t\tchar *ref = xstrfmt(\"refs/heads/%s\", default_branch);\n \n \t\tr = find_ref_by_name(refs, ref);\n \t\tfree(ref);\n+\t\tfree(default_branch);\n+\n \t\tif (r && oideq(&r->old_oid, &head->old_oid))\n \t\t\treturn copy_ref(r);\n \ndiff --git a/setup.c b/setup.c\nindex fec6bfd5fa..481b57d523 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2046,6 +2046,7 @@ void create_reference_database(unsigned int ref_storage_format,\n \t\t\t       const char *initial_branch, int quiet)\n {\n \tstruct strbuf err = STRBUF_INIT;\n+\tchar *to_free = NULL;\n \tint reinit = is_reinit();\n \n \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n@@ -2060,7 +2061,8 @@ void create_reference_database(unsigned int ref_storage_format,\n \t\tchar *ref;\n \n \t\tif (!initial_branch)\n-\t\t\tinitial_branch = git_default_branch_name(quiet);\n+\t\t\tinitial_branch = to_free =\n+\t\t\t\trepo_default_branch_name(the_repository, quiet);\n \n \t\tref = xstrfmt(\"refs/heads/%s\", initial_branch);\n \t\tif (check_refname_format(ref, 0) < 0)\n@@ -2077,6 +2079,7 @@ void create_reference_database(unsigned int ref_storage_format,\n \t\t\tinitial_branch);\n \n \tstrbuf_release(&err);\n+\tfree(to_free);\n }\n \n static int create_default_files(const char *template_path,\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494954","messageId":"afa918488473acf1b8931d7c3565f3cffafb8740.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 13/16] refs: remove `dwim_log()`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:14Z","receivedAt":"2024-05-17T08:19:18Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Remove `dwim_log()` in favor of `repo_dwim_log()` so that we can get rid\nof one more dependency on `the_repository`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/reflog.c | 2 +-\n reflog-walk.c    | 4 ++--\n reflog.c         | 2 +-\n refs.c           | 5 -----\n refs.h           | 1 -\n 5 files changed, 4 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex b4650cea16..0d2ff95c6e 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -378,7 +378,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n \t\tchar *ref;\n \t\tstruct expire_reflog_policy_cb cb = { .cmd = cmd };\n \n-\t\tif (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {\n+\t\tif (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {\n \t\t\tstatus |= error(_(\"%s points nowhere!\"), argv[i]);\n \t\t\tcontinue;\n \t\t}\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex f11b97e889..5f09552c5c 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -191,8 +191,8 @@ int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\treflogs = read_complete_reflog(branch);\n \t\tif (!reflogs || reflogs->nr == 0) {\n \t\t\tchar *b;\n-\t\t\tint ret = dwim_log(branch, strlen(branch),\n-\t\t\t\t\t   NULL, &b);\n+\t\t\tint ret = repo_dwim_log(the_repository, branch, strlen(branch),\n+\t\t\t\t\t\tNULL, &b);\n \t\t\tif (ret > 1)\n \t\t\t\tfree(b);\n \t\t\telse if (ret == 1) {\ndiff --git a/reflog.c b/reflog.c\nindex 8861c2d606..3c80950186 100644\n--- a/reflog.c\n+++ b/reflog.c\n@@ -409,7 +409,7 @@ int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)\n \tif (!spec)\n \t\treturn error(_(\"not a reflog: %s\"), rev);\n \n-\tif (!dwim_log(rev, spec - rev, NULL, &ref)) {\n+\tif (!repo_dwim_log(the_repository, rev, spec - rev, NULL, &ref)) {\n \t\tstatus |= error(_(\"no reflog for '%s'\"), rev);\n \t\tgoto cleanup;\n \t}\ndiff --git a/refs.c b/refs.c\nindex 83cd965a26..43c5fef734 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -775,11 +775,6 @@ int repo_dwim_log(struct repository *r, const char *str, int len,\n \treturn logs_found;\n }\n \n-int dwim_log(const char *str, int len, struct object_id *oid, char **log)\n-{\n-\treturn repo_dwim_log(the_repository, str, len, oid, log);\n-}\n-\n int is_per_worktree_ref(const char *refname)\n {\n \treturn starts_with(refname, \"refs/worktree/\") ||\ndiff --git a/refs.h b/refs.h\nindex e906dbb44a..82022d300c 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -164,7 +164,6 @@ int expand_ref(struct repository *r, const char *str, int len, struct object_id\n int repo_dwim_ref(struct repository *r, const char *str, int len,\n \t\t  struct object_id *oid, char **ref, int nonfatal_dangling_mark);\n int repo_dwim_log(struct repository *r, const char *str, int len, struct object_id *oid, char **ref);\n-int dwim_log(const char *str, int len, struct object_id *oid, char **ref);\n \n /*\n  * Retrieves the default branch name for newly-initialized repositories.\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494955","messageId":"c1a2dc4e6923b660b05a4aea006fba0559da13ed.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 14/16] refs/files: use correct repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:19Z","receivedAt":"2024-05-17T08:19:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"There are several places in the \"files\" backend where we use\n`the_repository` instead of the repository associated with the ref store\nitself. Adapt those to use the correct repository.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/files-backend.c | 23 +++++++++++++----------\n 1 file changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 62acd2721d..235c8580d1 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1237,7 +1237,8 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_\n /*\n  * Return true if the specified reference should be packed.\n  */\n-static int should_pack_ref(const char *refname,\n+static int should_pack_ref(struct files_ref_store *refs,\n+\t\t\t   const char *refname,\n \t\t\t   const struct object_id *oid, unsigned int ref_flags,\n \t\t\t   struct pack_refs_opts *opts)\n {\n@@ -1253,7 +1254,7 @@ static int should_pack_ref(const char *refname,\n \t\treturn 0;\n \n \t/* Do not pack broken refs: */\n-\tif (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))\n+\tif (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))\n \t\treturn 0;\n \n \tif (ref_excluded(opts->exclusions, refname))\n@@ -1285,14 +1286,14 @@ static int files_pack_refs(struct ref_store *ref_store,\n \tpacked_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);\n \n \titer = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,\n-\t\t\t\t\tthe_repository, 0);\n+\t\t\t\t\trefs->base.repo, 0);\n \twhile ((ok = ref_iterator_advance(iter)) == ITER_OK) {\n \t\t/*\n \t\t * If the loose reference can be packed, add an entry\n \t\t * in the packed ref cache. If the reference should be\n \t\t * pruned, also add it to refs_to_prune.\n \t\t */\n-\t\tif (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))\n+\t\tif (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))\n \t\t\tcontinue;\n \n \t\t/*\n@@ -1389,7 +1390,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)\n \treturn ret;\n }\n \n-static int write_ref_to_lockfile(struct ref_lock *lock,\n+static int write_ref_to_lockfile(struct files_ref_store *refs,\n+\t\t\t\t struct ref_lock *lock,\n \t\t\t\t const struct object_id *oid,\n \t\t\t\t int skip_oid_verification, struct strbuf *err);\n static int commit_ref_update(struct files_ref_store *refs,\n@@ -1537,7 +1539,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \t}\n \toidcpy(&lock->old_oid, &orig_oid);\n \n-\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n+\tif (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1557,7 +1559,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = LOG_REFS_NONE;\n-\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n+\tif (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1791,7 +1793,8 @@ static int files_log_ref_write(struct files_ref_store *refs,\n  * Write oid into the open lockfile, then close the lockfile. On\n  * errors, rollback the lockfile, fill in *err and return -1.\n  */\n-static int write_ref_to_lockfile(struct ref_lock *lock,\n+static int write_ref_to_lockfile(struct files_ref_store *refs,\n+\t\t\t\t struct ref_lock *lock,\n \t\t\t\t const struct object_id *oid,\n \t\t\t\t int skip_oid_verification, struct strbuf *err)\n {\n@@ -1800,7 +1803,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n \tint fd;\n \n \tif (!skip_oid_verification) {\n-\t\to = parse_object(the_repository, oid);\n+\t\to = parse_object(refs->base.repo, oid);\n \t\tif (!o) {\n \t\t\tstrbuf_addf(\n \t\t\t\terr,\n@@ -2571,7 +2574,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * value, so we don't need to write it.\n \t\t\t */\n \t\t} else if (write_ref_to_lockfile(\n-\t\t\t\t   lock, &update->new_oid,\n+\t\t\t\t   refs, lock, &update->new_oid,\n \t\t\t\t   update->flags & REF_SKIP_OID_VERIFICATION,\n \t\t\t\t   err)) {\n \t\t\tchar *write_err = strbuf_detach(err, NULL);\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494956","messageId":"20c2bb4cbbb8eb1604c9a6a650b36cb05cd1dbf0.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 15/16] refs/files: remove references to `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:24Z","receivedAt":"2024-05-17T08:19:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Remove references to `the_hash_algo` in favor of the hash algo specified\nby the repository associated with the files ref store.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/files-backend.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 235c8580d1..735a5acefe 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1822,7 +1822,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,\n \t\t}\n \t}\n \tfd = get_lock_file_fd(&lock->lk);\n-\tif (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||\n+\tif (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||\n \t    write_in_full(fd, &term, 1) < 0 ||\n \t    fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&lock->lk)) < 0 ||\n \t    close_ref_gently(lock) < 0) {\n@@ -3223,7 +3223,7 @@ static int files_reflog_expire(struct ref_store *ref_store,\n \t\t\trollback_lock_file(&reflog_lock);\n \t\t} else if (update &&\n \t\t\t   (write_in_full(get_lock_file_fd(&lock->lk),\n-\t\t\t\toid_to_hex(&cb.last_kept_oid), the_hash_algo->hexsz) < 0 ||\n+\t\t\t\toid_to_hex(&cb.last_kept_oid), refs->base.repo->hash_algo->hexsz) < 0 ||\n \t\t\t    write_str_in_full(get_lock_file_fd(&lock->lk), \"\\n\") < 0 ||\n \t\t\t    close_ref_gently(lock) < 0)) {\n \t\t\tstatus |= error(\"couldn't write %s\",\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"},{"id":"494957","messageId":"5ebe81d8c3410f88e5f6be6383fc301a48fb9eed.1715929858.git.ps@pks.im","threadId":"61496","inReplyTo":"cover.1715929858.git.ps@pks.im","subject":"[PATCH v2 16/16] refs/packed: remove references to `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-05-17T08:19:29Z","receivedAt":"2024-05-17T08:19:34Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Remove references to `the_hash_algo` in favor of the hash algo specified\nby the repository associated with the packed ref store.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/packed-backend.c | 32 ++++++++++++++++++++------------\n 1 file changed, 20 insertions(+), 12 deletions(-)\n\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex dfdd718eb9..78e26bcf41 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -200,6 +200,11 @@ static int release_snapshot(struct snapshot *snapshot)\n \t}\n }\n \n+static size_t snapshot_hexsz(const struct snapshot *snapshot)\n+{\n+\treturn snapshot->refs->base.repo->hash_algo->hexsz;\n+}\n+\n struct ref_store *packed_ref_store_init(struct repository *repo,\n \t\t\t\t\tconst char *gitdir,\n \t\t\t\t\tunsigned int store_flags)\n@@ -289,11 +294,13 @@ struct snapshot_record {\n \tsize_t len;\n };\n \n-static int cmp_packed_ref_records(const void *v1, const void *v2)\n+static int cmp_packed_ref_records(const void *v1, const void *v2,\n+\t\t\t\t  void *cb_data)\n {\n+\tconst struct snapshot *snapshot = cb_data;\n \tconst struct snapshot_record *e1 = v1, *e2 = v2;\n-\tconst char *r1 = e1->start + the_hash_algo->hexsz + 1;\n-\tconst char *r2 = e2->start + the_hash_algo->hexsz + 1;\n+\tconst char *r1 = e1->start + snapshot_hexsz(snapshot) + 1;\n+\tconst char *r2 = e2->start + snapshot_hexsz(snapshot) + 1;\n \n \twhile (1) {\n \t\tif (*r1 == '\\n')\n@@ -314,9 +321,9 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)\n  * refname.\n  */\n static int cmp_record_to_refname(const char *rec, const char *refname,\n-\t\t\t\t int start)\n+\t\t\t\t int start, const struct snapshot *snapshot)\n {\n-\tconst char *r1 = rec + the_hash_algo->hexsz + 1;\n+\tconst char *r1 = rec + snapshot_hexsz(snapshot) + 1;\n \tconst char *r2 = refname;\n \n \twhile (1) {\n@@ -363,7 +370,7 @@ static void sort_snapshot(struct snapshot *snapshot)\n \t\tif (!eol)\n \t\t\t/* The safety check should prevent this. */\n \t\t\tBUG(\"unterminated line found in packed-refs\");\n-\t\tif (eol - pos < the_hash_algo->hexsz + 2)\n+\t\tif (eol - pos < snapshot_hexsz(snapshot) + 2)\n \t\t\tdie_invalid_line(snapshot->refs->path,\n \t\t\t\t\t pos, eof - pos);\n \t\teol++;\n@@ -389,7 +396,7 @@ static void sort_snapshot(struct snapshot *snapshot)\n \t\tif (sorted &&\n \t\t    nr > 1 &&\n \t\t    cmp_packed_ref_records(&records[nr - 2],\n-\t\t\t\t\t   &records[nr - 1]) >= 0)\n+\t\t\t\t\t   &records[nr - 1], snapshot) >= 0)\n \t\t\tsorted = 0;\n \n \t\tpos = eol;\n@@ -399,7 +406,7 @@ static void sort_snapshot(struct snapshot *snapshot)\n \t\tgoto cleanup;\n \n \t/* We need to sort the memory. First we sort the records array: */\n-\tQSORT(records, nr, cmp_packed_ref_records);\n+\tQSORT_S(records, nr, cmp_packed_ref_records, snapshot);\n \n \t/*\n \t * Allocate a new chunk of memory, and copy the old memory to\n@@ -475,7 +482,8 @@ static void verify_buffer_safe(struct snapshot *snapshot)\n \t\treturn;\n \n \tlast_line = find_start_of_record(start, eof - 1);\n-\tif (*(eof - 1) != '\\n' || eof - last_line < the_hash_algo->hexsz + 2)\n+\tif (*(eof - 1) != '\\n' ||\n+\t    eof - last_line < snapshot_hexsz(snapshot) + 2)\n \t\tdie_invalid_line(snapshot->refs->path,\n \t\t\t\t last_line, eof - last_line);\n }\n@@ -570,7 +578,7 @@ static const char *find_reference_location_1(struct snapshot *snapshot,\n \n \t\tmid = lo + (hi - lo) / 2;\n \t\trec = find_start_of_record(lo, mid);\n-\t\tcmp = cmp_record_to_refname(rec, refname, start);\n+\t\tcmp = cmp_record_to_refname(rec, refname, start, snapshot);\n \t\tif (cmp < 0) {\n \t\t\tlo = find_end_of_record(mid, hi);\n \t\t} else if (cmp > 0) {\n@@ -867,7 +875,7 @@ static int next_record(struct packed_ref_iterator *iter)\n \titer->base.flags = REF_ISPACKED;\n \tp = iter->pos;\n \n-\tif (iter->eof - p < the_hash_algo->hexsz + 2 ||\n+\tif (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||\n \t    parse_oid_hex(p, &iter->oid, &p) ||\n \t    !isspace(*p++))\n \t\tdie_invalid_line(iter->snapshot->refs->path,\n@@ -897,7 +905,7 @@ static int next_record(struct packed_ref_iterator *iter)\n \n \tif (iter->pos < iter->eof && *iter->pos == '^') {\n \t\tp = iter->pos + 1;\n-\t\tif (iter->eof - p < the_hash_algo->hexsz + 1 ||\n+\t\tif (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||\n \t\t    parse_oid_hex(p, &iter->peeled, &p) ||\n \t\t    *p++ != '\\n')\n \t\t\tdie_invalid_line(iter->snapshot->refs->path,\n-- \n2.45.1.190.g19fe900cfc.dirty\n\n"}]}