{"thread":{"id":"60666","subject":"[PATCH 0/6] worktree: initialize refdb via ref backends","startedAt":"2023-12-28T09:59:50Z","lastAt":"2024-01-16T17:53:44Z","messageCount":21,"participants":["Patrick Steinhardt","Junio C Hamano","Eric Sunshine","Karthik Nayak"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"486107","messageId":"cover.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":null,"subject":"[PATCH 0/6] worktree: initialize refdb via ref backends","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T09:59:47Z","receivedAt":"2023-12-28T09:59:50Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nwhen initializing worktrees we manually create the on-disk data\nstructures required for the ref backend in \"worktree.c\". This works just\nfine right now where we only have a single user-exposed ref backend, but\nit will become unwieldy once we have multiple ref backends. This patch\nseries thus refactors how we initialize worktrees so that we can use\n`refs_init_db()` to initialize required files for us.\n\nThis patch series conflicts with ps/refstorage-extension. The conflict\ncan be solved as shown below. I'm happy to defer this patch series\nthough until the topic has landed on `master` in case this causes\nissues.\n\nPatrick\n\ndiff --cc setup.c\nindex f2d55994e2,4712bba6f8..0000000000\n--- a/setup.c\n+++ b/setup.c\n@@@ -1904,7 -1926,23 +1926,8 @@@ void create_reference_database(int ref_\n  \tstruct strbuf err = STRBUF_INIT;\n  \tint reinit = is_reinit();\n  \n -\t/*\n -\t * We need to create a \"refs\" dir in any case so that older versions of\n -\t * Git can tell that this is a repository. This serves two main purposes:\n -\t *\n -\t * - Clients will know to stop walking the parent-directory chain when\n -\t *   detecting the Git repository. Otherwise they may end up detecting\n -\t *   a Git repository in a parent directory instead.\n -\t *\n -\t * - Instead of failing to detect a repository with unknown reference\n -\t *   format altogether, old clients will print an error saying that\n -\t *   they do not understand the reference format extension.\n -\t */\n -\tsafe_create_dir(git_path(\"refs\"), 1);\n -\tadjust_shared_perm(git_path(\"refs\"));\n -\n+ \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n -\tif (refs_init_db(&err))\n +\tif (refs_init_db(get_main_ref_store(the_repository), 0, &err))\n  \t\tdie(\"failed to set up refs db: %s\", err.buf);\n  \n  \t/*\ndiff --cc worktree.c\nindex 085f2cc41a,9702ed0308..0000000000\n--- a/worktree.c\n+++ b/worktree.c\n@@@ -79,7 -75,8 +80,8 @@@ static struct worktree *get_main_worktr\n  \treturn worktree;\n  }\n  \n- struct worktree *get_linked_worktree(const char *id)\n -static struct worktree *get_linked_worktree(const char *id,\n -\t\t\t\t\t    int skip_reading_head)\n++struct worktree *get_linked_worktree(const char *id,\n++\t\t\t\t     int skip_reading_head)\n  {\n  \tstruct worktree *worktree = NULL;\n  \tstruct strbuf path = STRBUF_INIT;\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9d935bee84..558c5537f5 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -502,7 +502,7 @@ static int add_worktree(const char *path, const char *refname,\n \t/*\n \t * Set up the ref store of the worktree and create the HEAD reference.\n \t */\n-\twt = get_linked_worktree(name);\n+\twt = get_linked_worktree(name, 1);\n \tif (!wt) {\n \t\tret = error(_(\"could not find created worktree '%s'\"), name);\n \t\tgoto done;\ndiff --git a/worktree.h b/worktree.h\nindex 8a75691eac..f14784a2ff 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -61,7 +61,8 @@ struct worktree *find_worktree(struct worktree **list,\n  * Look up the worktree corresponding to `id`, or NULL of no such worktree\n  * exists.\n  */\n-struct worktree *get_linked_worktree(const char *id);\n+struct worktree *get_linked_worktree(const char *id,\n+\t\t\t\t     int skip_reading_head);\n \n /*\n  * Return the worktree corresponding to `path`, or NULL if no such worktree\n\nPatrick Steinhardt (6):\n  refs: prepare `refs_init_db()` for initializing worktree refs\n  setup: move creation of \"refs/\" into the files backend\n  refs/files: skip creation of \"refs/{heads,tags}\" for worktrees\n  builtin/worktree: move setup of commondir file earlier\n  worktree: expose interface to look up worktree by name\n  builtin/worktree: create refdb via ref backend\n\n builtin/worktree.c    | 53 ++++++++++++++++++++-----------------------\n refs.c                |  6 ++---\n refs.h                |  4 +++-\n refs/debug.c          |  4 ++--\n refs/files-backend.c  | 37 +++++++++++++++++++++++++-----\n refs/packed-backend.c |  1 +\n refs/refs-internal.h  |  4 +++-\n setup.c               | 17 +-------------\n worktree.c            | 25 ++++++++++++--------\n worktree.h            | 11 +++++++++\n 10 files changed, 94 insertions(+), 68 deletions(-)\n\n\nbase-commit: e79552d19784ee7f4bbce278fe25f93fbda196fa\n-- \n2.43.GIT\n\n"},{"id":"486108","messageId":"6cb4e0a99fff52c35ea293f855fd3a34bcba7ab1.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 1/6] refs: prepare `refs_init_db()` for initializing worktree refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T09:59:51Z","receivedAt":"2023-12-28T09:59:54Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The purpose of `refs_init_db()` is to initialize the on-disk files of a\nnew ref database. The function is quite inflexible right now though, as\ncallers can neither specify the `struct ref_store` nor can they pass any\nflags.\n\nRefactor the interface to accept both of these. This will be required so\nthat we can start initializing per-worktree ref databases via the ref\nbackend instead of open-coding the initialization in \"worktree.c\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.c                | 6 ++----\n refs.h                | 2 +-\n refs/debug.c          | 4 ++--\n refs/files-backend.c  | 4 +++-\n refs/packed-backend.c | 1 +\n refs/refs-internal.h  | 4 +++-\n setup.c               | 2 +-\n 7 files changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 16bfa21df7..87e2659db7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1928,11 +1928,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,\n }\n \n /* backend functions */\n-int refs_init_db(struct strbuf *err)\n+int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n {\n-\tstruct ref_store *refs = get_main_ref_store(the_repository);\n-\n-\treturn refs->be->init_db(refs, err);\n+\treturn refs->be->init_db(refs, flags, err);\n }\n \n const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\ndiff --git a/refs.h b/refs.h\nindex ff113bb12a..6090e92578 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -123,7 +123,7 @@ int should_autocreate_reflog(const char *refname);\n \n int is_branch(const char *refname);\n \n-int refs_init_db(struct strbuf *err);\n+int refs_init_db(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 83b7a0ba65..c061def8b5 100644\n--- a/refs/debug.c\n+++ b/refs/debug.c\n@@ -33,10 +33,10 @@ 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, struct strbuf *err)\n+static int debug_init_db(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, err);\n+\tint res = drefs->refs->be->init_db(drefs->refs, flags, err);\n \ttrace_printf_key(&trace_refs, \"init_db: %d\\n\", res);\n \treturn res;\n }\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ad8b1d143f..387eeb5037 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3220,7 +3220,9 @@ 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, struct strbuf *err UNUSED)\n+static int files_init_db(struct ref_store *ref_store,\n+\t\t\t int flags UNUSED,\n+\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\");\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex b9fa097a29..3f10bccf44 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -1246,6 +1246,7 @@ 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 {\n \t/* Nothing to do. */\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 4af83bf9a5..a33b28c19d 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -529,7 +529,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, struct strbuf *err);\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 \n typedef int ref_transaction_prepare_fn(struct ref_store *refs,\n \t\t\t\t       struct ref_transaction *transaction,\ndiff --git a/setup.c b/setup.c\nindex bc90bbd033..a4eb2a38ac 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1919,7 +1919,7 @@ void create_reference_database(const char *initial_branch, int quiet)\n \tsafe_create_dir(git_path(\"refs\"), 1);\n \tadjust_shared_perm(git_path(\"refs\"));\n \n-\tif (refs_init_db(&err))\n+\tif (refs_init_db(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.43.GIT\n\n"},{"id":"486109","messageId":"ae013eaa4aba0d68172ff03dbe9f2c2bca596285.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 2/6] setup: move creation of \"refs/\" into the files backend","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T09:59:56Z","receivedAt":"2023-12-28T09:59:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When creating the ref database we unconditionally create the \"refs/\"\ndirectory in \"setup.c\". This is a mandatory prerequisite for all Git\nrepositories regardless of the ref backend in use, because Git will be\nunable to detect the directory as a repository if \"refs/\" doesn't exist.\n\nWe are about to add another new caller that will want to create a ref\ndatabase when creating worktrees. We would require the same logic to\ncreate the \"refs/\" directory even though the caller really should not\ncare about such low-level details. Ideally, the ref database should be\nfully initialized after calling `refs_init_db()`.\n\nMove the code to create the directory into the files backend itself to\nmake it so. This means that future ref backends will also need to have\nequivalent logic around to ensure that the directory exists, but it\nseems a lot more sensible to have it this way round than to require\ncallers to create the directory themselves.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/files-backend.c | 17 +++++++++++++++++\n setup.c              | 15 ---------------\n 2 files changed, 17 insertions(+), 15 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 387eeb5037..ed47c5dc08 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3228,9 +3228,26 @@ static int files_init_db(struct ref_store *ref_store,\n \t\tfiles_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\t/*\n+\t * We need to create a \"refs\" dir in any case so that older versions of\n+\t * Git can tell that this is a repository. This serves two main purposes:\n+\t *\n+\t * - Clients will know to stop walking the parent-directory chain when\n+\t *   detecting the Git repository. Otherwise they may end up detecting\n+\t *   a Git repository in a parent directory instead.\n+\t *\n+\t * - Instead of failing to detect a repository with unknown reference\n+\t *   format altogether, old clients will print an error saying that\n+\t *   they do not understand the reference format extension.\n+\t */\n+\tstrbuf_addf(&sb, \"%s/refs\", ref_store->gitdir);\n+\tsafe_create_dir(sb.buf, 1);\n+\tadjust_shared_perm(sb.buf);\n+\n \t/*\n \t * Create .git/refs/{heads,tags}\n \t */\n+\tstrbuf_reset(&sb);\n \tfiles_ref_path(refs, &sb, \"refs/heads\");\n \tsafe_create_dir(sb.buf, 1);\n \ndiff --git a/setup.c b/setup.c\nindex a4eb2a38ac..f2d55994e2 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1904,21 +1904,6 @@ void create_reference_database(const char *initial_branch, int quiet)\n \tstruct strbuf err = STRBUF_INIT;\n \tint reinit = is_reinit();\n \n-\t/*\n-\t * We need to create a \"refs\" dir in any case so that older versions of\n-\t * Git can tell that this is a repository. This serves two main purposes:\n-\t *\n-\t * - Clients will know to stop walking the parent-directory chain when\n-\t *   detecting the Git repository. Otherwise they may end up detecting\n-\t *   a Git repository in a parent directory instead.\n-\t *\n-\t * - Instead of failing to detect a repository with unknown reference\n-\t *   format altogether, old clients will print an error saying that\n-\t *   they do not understand the reference format extension.\n-\t */\n-\tsafe_create_dir(git_path(\"refs\"), 1);\n-\tadjust_shared_perm(git_path(\"refs\"));\n-\n \tif (refs_init_db(get_main_ref_store(the_repository), 0, &err))\n \t\tdie(\"failed to set up refs db: %s\", err.buf);\n \n-- \n2.43.GIT\n\n"},{"id":"486110","messageId":"3cf6ceb274d20ce76d0be65e4362a33579627052.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 3/6] refs/files: skip creation of \"refs/{heads,tags}\" for worktrees","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T10:00:00Z","receivedAt":"2023-12-28T10:00:03Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The files ref backend will create both \"refs/heads\" and \"refs/tags\" in\nthe Git directory. While this logic makes sense for normal repositories,\nit does not fo worktrees because those refs are \"common\" refs that would\nalways be contained in the main repository's ref database.\n\nIntroduce a new flag telling the backend that it is expected to create a\nper-worktree ref database and skip creation of these dirs in the files\nbackend when the flag is set. No other backends (currently) need\nworktree-specific logic, so this is the only required change to start\ncreating per-worktree ref databases via `refs_init_db()`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.h               |  2 ++\n refs/files-backend.c | 22 ++++++++++++++--------\n 2 files changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex 6090e92578..8ed890841b 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -123,6 +123,8 @@ 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+\n int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);\n \n /*\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ed47c5dc08..a82d6c453f 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3221,7 +3221,7 @@ static int files_reflog_expire(struct ref_store *ref_store,\n }\n \n static int files_init_db(struct ref_store *ref_store,\n-\t\t\t int flags UNUSED,\n+\t\t\t int flags,\n \t\t\t struct strbuf *err UNUSED)\n {\n \tstruct files_ref_store *refs =\n@@ -3245,15 +3245,21 @@ static int files_init_db(struct ref_store *ref_store,\n \tadjust_shared_perm(sb.buf);\n \n \t/*\n-\t * Create .git/refs/{heads,tags}\n+\t * There is no need to create directories for common refs when creating\n+\t * a worktree ref store.\n \t */\n-\tstrbuf_reset(&sb);\n-\tfiles_ref_path(refs, &sb, \"refs/heads\");\n-\tsafe_create_dir(sb.buf, 1);\n+\tif (!(flags & REFS_INIT_DB_IS_WORKTREE)) {\n+\t\t/*\n+\t\t * Create .git/refs/{heads,tags}\n+\t\t */\n+\t\tstrbuf_reset(&sb);\n+\t\tfiles_ref_path(refs, &sb, \"refs/heads\");\n+\t\tsafe_create_dir(sb.buf, 1);\n \n-\tstrbuf_reset(&sb);\n-\tfiles_ref_path(refs, &sb, \"refs/tags\");\n-\tsafe_create_dir(sb.buf, 1);\n+\t\tstrbuf_reset(&sb);\n+\t\tfiles_ref_path(refs, &sb, \"refs/tags\");\n+\t\tsafe_create_dir(sb.buf, 1);\n+\t}\n \n \tstrbuf_release(&sb);\n \treturn 0;\n-- \n2.43.GIT\n\n"},{"id":"486111","messageId":"1a6337fc513f4c3750649a940a84be94b5855a35.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 4/6] builtin/worktree: move setup of commondir file earlier","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T10:00:04Z","receivedAt":"2023-12-28T10:00:07Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Shuffle around how we create supporting worktree files so that we first\nensure that the worktree has all link files (\"gitdir\", \"commondir\")\nbefore we try to initialize the ref database by writing \"HEAD\". This\nwill be required by a subsequent commit where we start to initialize the\nref database via `refs_init_db()`, which will require an initialized\n`struct worktree *`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/worktree.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 4ac1621541..58937a2a68 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -495,6 +495,10 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_realpath(&realpath, get_git_common_dir(), 1);\n \twrite_file(sb_git.buf, \"gitdir: %s/worktrees/%s\",\n \t\t   realpath.buf, name);\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n+\twrite_file(sb.buf, \"../..\");\n+\n \t/*\n \t * This is to keep resolve_ref() happy. We need a valid HEAD\n \t * or is_git_directory() will reject the directory. Any value which\n@@ -505,9 +509,6 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n \twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n-\twrite_file(sb.buf, \"../..\");\n \n \t/*\n \t * If the current worktree has sparse-checkout enabled, then copy\n-- \n2.43.GIT\n\n"},{"id":"486112","messageId":"f344a915e98e9c7be6aaf535cf0acfd08fb06b7d.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 5/6] worktree: expose interface to look up worktree by name","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T10:00:09Z","receivedAt":"2023-12-28T10:00:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our worktree interfaces do not provide a way to look up a worktree by\nits name. Expose `get_linked_worktree()` to allow for this usecase. As\ncallers are responsible for freeing this worktree, introduce a new\nfunction `free_worktree()` that does so.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n worktree.c | 25 +++++++++++++++----------\n worktree.h | 11 +++++++++++\n 2 files changed, 26 insertions(+), 10 deletions(-)\n\ndiff --git a/worktree.c b/worktree.c\nindex a56a6c2a3d..085f2cc41a 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -12,18 +12,23 @@\n #include \"wt-status.h\"\n #include \"config.h\"\n \n+void free_worktree(struct worktree *worktree)\n+{\n+\tif (!worktree)\n+\t\treturn;\n+\tfree(worktree->path);\n+\tfree(worktree->id);\n+\tfree(worktree->head_ref);\n+\tfree(worktree->lock_reason);\n+\tfree(worktree->prune_reason);\n+\tfree(worktree);\n+}\n+\n void free_worktrees(struct worktree **worktrees)\n {\n \tint i = 0;\n-\n-\tfor (i = 0; worktrees[i]; i++) {\n-\t\tfree(worktrees[i]->path);\n-\t\tfree(worktrees[i]->id);\n-\t\tfree(worktrees[i]->head_ref);\n-\t\tfree(worktrees[i]->lock_reason);\n-\t\tfree(worktrees[i]->prune_reason);\n-\t\tfree(worktrees[i]);\n-\t}\n+\tfor (i = 0; worktrees[i]; i++)\n+\t\tfree_worktree(worktrees[i]);\n \tfree (worktrees);\n }\n \n@@ -74,7 +79,7 @@ static struct worktree *get_main_worktree(void)\n \treturn worktree;\n }\n \n-static struct worktree *get_linked_worktree(const char *id)\n+struct worktree *get_linked_worktree(const char *id)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\ndiff --git a/worktree.h b/worktree.h\nindex ce45b66de9..8a75691eac 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -57,6 +57,12 @@ struct worktree *find_worktree(struct worktree **list,\n \t\t\t       const char *prefix,\n \t\t\t       const char *arg);\n \n+/*\n+ * Look up the worktree corresponding to `id`, or NULL of no such worktree\n+ * exists.\n+ */\n+struct worktree *get_linked_worktree(const char *id);\n+\n /*\n  * Return the worktree corresponding to `path`, or NULL if no such worktree\n  * exists.\n@@ -134,6 +140,11 @@ void repair_worktrees(worktree_repair_fn, void *cb_data);\n  */\n void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);\n \n+/*\n+ * Free up the memory for a worktree.\n+ */\n+void free_worktree(struct worktree *);\n+\n /*\n  * Free up the memory for worktree(s)\n  */\n-- \n2.43.GIT\n\n"},{"id":"486113","messageId":"aae969301fa6792263d32362b36d071de4f6ed94.1703754513.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH 6/6] builtin/worktree: create refdb via ref backend","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T10:00:13Z","receivedAt":"2023-12-28T10:00:16Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When creating a worktree we create the worktree's ref database manually\nby first writing a \"HEAD\" file so that the directory is recognized as a\nGit repository by other commands, and then running git-update-ref(1) or\ngit-symbolic-ref(1) to write the actual value. But while this is fine\nfor the files backend, this logic simply assumes too much about how the\nref backend works and will leave behind an invalid ref database once any\nother ref backend lands.\n\nRefactor the code to instead use `refs_init_db()` to initialize the ref\ndatabase so that git-worktree(1) itself does not need to know about how\nto initialize it. This will allow future ref backends to customize how\nthe per-worktree ref database is set up. Furthermore, as we now already\nhave a worktree ref store around, we can also avoid spawning external\ncommands to write the HEAD reference and instead use the refs API to do\nso.\n\nNote that we do not have an equivalent to passing the `--quiet` flag to\ngit-symbolic-ref(1) as we did before. This flag does not have an effect\nanyway though, as git-symbolic-ref(1) only honors it when reading a\nsymref, but never when writing one.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/worktree.c | 48 +++++++++++++++++++++-------------------------\n 1 file changed, 22 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 58937a2a68..9d935bee84 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -416,7 +416,6 @@ static int add_worktree(const char *path, const char *refname,\n \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n \tstruct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;\n \tconst char *name;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strvec child_env = STRVEC_INIT;\n \tunsigned int counter = 0;\n \tint len, ret;\n@@ -424,7 +423,8 @@ static int add_worktree(const char *path, const char *refname,\n \tstruct commit *commit = NULL;\n \tint is_branch = 0;\n \tstruct strbuf sb_name = STRBUF_INIT;\n-\tstruct worktree **worktrees;\n+\tstruct worktree **worktrees, *wt = NULL;\n+\tstruct ref_store *wt_refs;\n \n \tworktrees = get_worktrees();\n \tcheck_candidate_path(path, opts->force, worktrees, \"add\");\n@@ -500,15 +500,26 @@ static int add_worktree(const char *path, const char *refname,\n \twrite_file(sb.buf, \"../..\");\n \n \t/*\n-\t * This is to keep resolve_ref() happy. We need a valid HEAD\n-\t * or is_git_directory() will reject the directory. Any value which\n-\t * looks like an object ID will do since it will be immediately\n-\t * replaced by the symbolic-ref or update-ref invocation in the new\n-\t * worktree.\n+\t * Set up the ref store of the worktree and create the HEAD reference.\n \t */\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n-\twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n+\twt = get_linked_worktree(name);\n+\tif (!wt) {\n+\t\tret = error(_(\"could not find created worktree '%s'\"), name);\n+\t\tgoto done;\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+\tif (ret)\n+\t\tgoto done;\n+\n+\tif (!is_branch && commit)\n+\t\tret = refs_update_ref(wt_refs, NULL, \"HEAD\", &commit->object.oid,\n+\t\t\t\t      NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\telse\n+\t\tret = refs_create_symref(wt_refs, \"HEAD\", symref.buf, NULL);\n+\tif (ret)\n+\t\tgoto done;\n \n \t/*\n \t * If the current worktree has sparse-checkout enabled, then copy\n@@ -527,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,\n \n \tstrvec_pushf(&child_env, \"%s=%s\", GIT_DIR_ENVIRONMENT, sb_git.buf);\n \tstrvec_pushf(&child_env, \"%s=%s\", GIT_WORK_TREE_ENVIRONMENT, path);\n-\tcp.git_cmd = 1;\n-\n-\tif (!is_branch && commit) {\n-\t\tstrvec_pushl(&cp.args, \"update-ref\", \"HEAD\",\n-\t\t\t     oid_to_hex(&commit->object.oid), NULL);\n-\t} else {\n-\t\tstrvec_pushl(&cp.args, \"symbolic-ref\", \"HEAD\",\n-\t\t\t     symref.buf, NULL);\n-\t\tif (opts->quiet)\n-\t\t\tstrvec_push(&cp.args, \"--quiet\");\n-\t}\n-\n-\tstrvec_pushv(&cp.env, child_env.v);\n-\tret = run_command(&cp);\n-\tif (ret)\n-\t\tgoto done;\n \n \tif (opts->orphan &&\n \t    (ret = make_worktree_orphan(refname, opts, &child_env)))\n@@ -588,6 +583,7 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_release(&sb_git);\n \tstrbuf_release(&sb_name);\n \tstrbuf_release(&realpath);\n+\tfree_worktree(wt);\n \treturn ret;\n }\n \n-- \n2.43.GIT\n\n"},{"id":"486132","messageId":"xmqqedf6gpt8.fsf@gitster.g","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"Re: [PATCH 0/6] worktree: initialize refdb via ref backends","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-12-28T18:11:31Z","receivedAt":"2023-12-28T18:11:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> when initializing worktrees we manually create the on-disk data\n> structures required for the ref backend in \"worktree.c\". This works just\n> fine right now where we only have a single user-exposed ref backend, but\n> it will become unwieldy once we have multiple ref backends. This patch\n> series thus refactors how we initialize worktrees so that we can use\n> `refs_init_db()` to initialize required files for us.\n>\n> This patch series conflicts with ps/refstorage-extension. The conflict\n> can be solved as shown below. I'm happy to defer this patch series\n> though until the topic has landed on `master` in case this causes\n> issues.\n\nResolution is not all that bad, but the change in function signature\nmeans comments/explanations near both the caller and the callee of\nthe get_linked_worktree() function may need updating, I would think.\nFor example, ...\n\n> diff --git a/worktree.h b/worktree.h\n> index 8a75691eac..f14784a2ff 100644\n> --- a/worktree.h\n> +++ b/worktree.h\n> @@ -61,7 +61,8 @@ struct worktree *find_worktree(struct worktree **list,\n>   * Look up the worktree corresponding to `id`, or NULL of no such worktree\n>   * exists.\n>   */\n> -struct worktree *get_linked_worktree(const char *id);\n> +struct worktree *get_linked_worktree(const char *id,\n> +\t\t\t\t     int skip_reading_head);\n\n... this now needs to help developers who may want to add new\ncallers what to pass in \"skip_reading_head\" and why.\n\nWe may indeed want to build this on top of the refstorage-extansion\nthing, as it seems to be relatively close to completion.\n\nThanks (and a happy new year).\n"},{"id":"486139","messageId":"ZY3TMy75mYzz0Pab@framework","threadId":"60666","inReplyTo":"xmqqedf6gpt8.fsf@gitster.g","subject":"Re: [PATCH 0/6] worktree: initialize refdb via ref backends","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T19:57:39Z","receivedAt":"2023-12-28T19:57:46Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Dec 28, 2023 at 10:11:31AM -0800, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > when initializing worktrees we manually create the on-disk data\n> > structures required for the ref backend in \"worktree.c\". This works just\n> > fine right now where we only have a single user-exposed ref backend, but\n> > it will become unwieldy once we have multiple ref backends. This patch\n> > series thus refactors how we initialize worktrees so that we can use\n> > `refs_init_db()` to initialize required files for us.\n> >\n> > This patch series conflicts with ps/refstorage-extension. The conflict\n> > can be solved as shown below. I'm happy to defer this patch series\n> > though until the topic has landed on `master` in case this causes\n> > issues.\n> \n> Resolution is not all that bad, but the change in function signature\n> means comments/explanations near both the caller and the callee of\n> the get_linked_worktree() function may need updating, I would think.\n> For example, ...\n> \n> > diff --git a/worktree.h b/worktree.h\n> > index 8a75691eac..f14784a2ff 100644\n> > --- a/worktree.h\n> > +++ b/worktree.h\n> > @@ -61,7 +61,8 @@ struct worktree *find_worktree(struct worktree **list,\n> >   * Look up the worktree corresponding to `id`, or NULL of no such worktree\n> >   * exists.\n> >   */\n> > -struct worktree *get_linked_worktree(const char *id);\n> > +struct worktree *get_linked_worktree(const char *id,\n> > +\t\t\t\t     int skip_reading_head);\n> \n> ... this now needs to help developers who may want to add new\n> callers what to pass in \"skip_reading_head\" and why.\n> \n> We may indeed want to build this on top of the refstorage-extansion\n> thing, as it seems to be relatively close to completion.\n\nFair enough. I'll wait for the refstorage extension topic to hit `next`\nor `master` first so as to not build deep dependency chains when things\nmay still move around. I don't mind waiting another one or two weeks,\nespecially during holidays where things are moving slower anyway.\n\n> Thanks (and a happy new year).\n\nThanks, the same to you, too.\n\nPatrick\n"},{"id":"486161","messageId":"CAPig+cRWCFdVd_+By2T-sP58u22OcgDQogSS0UP5ZYYf2K5W_A@mail.gmail.com","threadId":"60666","inReplyTo":"3cf6ceb274d20ce76d0be65e4362a33579627052.1703754513.git.ps@pks.im","subject":"Re: [PATCH 3/6] refs/files: skip creation of \"refs/{heads,tags}\" for worktrees","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-12-29T10:35:49Z","receivedAt":"2023-12-29T10:36:01Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Dec 29, 2023 at 5:16 AM Patrick Steinhardt <ps@pks.im> wrote:\n> The files ref backend will create both \"refs/heads\" and \"refs/tags\" in\n> the Git directory. While this logic makes sense for normal repositories,\n> it does not fo worktrees because those refs are \"common\" refs that would\n> always be contained in the main repository's ref database.\n\ns/fo/for/\n\n(not worth a reroll)\n\n> Introduce a new flag telling the backend that it is expected to create a\n> per-worktree ref database and skip creation of these dirs in the files\n> backend when the flag is set. No other backends (currently) need\n> worktree-specific logic, so this is the only required change to start\n> creating per-worktree ref databases via `refs_init_db()`.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n"},{"id":"486194","messageId":"CAOLa=ZTR6aW5aoxcMOS3U3TL1VxSfmyVno9fu7B5201pJTqyyg@mail.gmail.com","threadId":"60666","inReplyTo":"ae013eaa4aba0d68172ff03dbe9f2c2bca596285.1703754513.git.ps@pks.im","subject":"Re: [PATCH 2/6] setup: move creation of \"refs/\" into the files backend","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-02T13:23:18Z","receivedAt":"2024-01-02T13:23:19Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Move the code to create the directory into the files backend itself to\n> make it so. This means that future ref backends will also need to have\n> equivalent logic around to ensure that the directory exists, but it\n> seems a lot more sensible to have it this way round than to require\n> callers to create the directory themselves.\n>\n\nWhy not move it to refs.c:refs_init_db() instead? this way each\nimplementation doesn't have to do it?\n\n@@ -2020,14 +2024,30 @@ const char *refs_resolve_ref_unsafe(struct\nref_store *refs,\n /* backend functions */\n int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n {\n+\t/*\n+\t * We need to create a \"refs\" dir in any case so that older versions of\n+\t * Git can tell that this is a repository. This serves two main\n+\t * purposes:\n+\t *\n+\t * - Clients will know to stop walking the parent-directory chain when\n+\t *   detecting the Git repository. Otherwise they may end up detecting\n+\t *   a Git repository in a parent directory instead.\n+\t *\n+\t * - Instead of failing to detect a repository with unknown reference\n+\t *   format altogether, old clients will print an error saying that\n+\t *   they do not understand the reference format extension.\n+\t */\n+\tsafe_create_dir(git_path(\"refs\"), 1);\n+\tadjust_shared_perm(git_path(\"refs\"));\n+\n \treturn refs->be->init_db(refs, flags, err);\n }\n"},{"id":"486247","messageId":"ZZUb0rj7be6wLQz5@tanuki","threadId":"60666","inReplyTo":"CAOLa=ZTR6aW5aoxcMOS3U3TL1VxSfmyVno9fu7B5201pJTqyyg@mail.gmail.com","subject":"Re: [PATCH 2/6] setup: move creation of \"refs/\" into the files backend","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T08:33:22Z","receivedAt":"2024-01-03T08:33:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Jan 02, 2024 at 05:23:18AM -0800, Karthik Nayak wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > Move the code to create the directory into the files backend itself to\n> > make it so. This means that future ref backends will also need to have\n> > equivalent logic around to ensure that the directory exists, but it\n> > seems a lot more sensible to have it this way round than to require\n> > callers to create the directory themselves.\n> >\n> \n> Why not move it to refs.c:refs_init_db() instead? this way each\n> implementation doesn't have to do it?\n\nTrue, that would be another possibility. But I think it is conceptually\nunclean to split up creation of the refdb into multiple locations. The\n\"files\" backend already has to create \"refs/heads/\" and \"refs/tags/\",\nand the \"reftable\" backend will set up \"refs/heads\" as a file so that\nit's impossible to create branches as loose files by accident. So both\ndo have specific knowledge around how exactly this directory hierarchy\nshould look like, and thus I think it is sensible to make the code self\ncontained inside of the backends.\n\nMy opinion on this would be different if we expected a proliferation of\nbackends to happen, but that's quite unlikely. Furthermore, we may at\nsome point decide that repos don't need \"refs/\" and/or \"HEAD\" at all\nanymore, at which point it is easier to drop the creation of those files\nand dirs from the reftable backend.\n\nI'll update the commit message to include these considerations.\n\nPatrick\n"},{"id":"486385","messageId":"cover.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1703754513.git.ps@pks.im","subject":"[PATCH v2 0/6] worktree: initialize refdb via ref backends","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:22Z","receivedAt":"2024-01-08T10:05:27Z","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 refactors the\ninitialization of worktree refdbs to use the refs API.\n\nChanges compared to v1:\n\n  - Improved commit messages.\n\n  - This series is now based on `ps/refstorage-extension`, 1b2234079b\n    (t9500: write \"extensions.refstorage\" into config, 2023-12-29).\n    While there is no functional dependency between those series,\n    merging both topics causes a merge conflict.\n\nPatrick\n\nPatrick Steinhardt (6):\n  refs: prepare `refs_init_db()` for initializing worktree refs\n  setup: move creation of \"refs/\" into the files backend\n  refs/files: skip creation of \"refs/{heads,tags}\" for worktrees\n  builtin/worktree: move setup of commondir file earlier\n  worktree: expose interface to look up worktree by name\n  builtin/worktree: create refdb via ref backend\n\n builtin/worktree.c    | 53 ++++++++++++++++++++-----------------------\n refs.c                |  6 ++---\n refs.h                |  4 +++-\n refs/debug.c          |  4 ++--\n refs/files-backend.c  | 37 +++++++++++++++++++++++++-----\n refs/packed-backend.c |  1 +\n refs/refs-internal.h  |  4 +++-\n setup.c               | 17 +-------------\n worktree.c            | 27 +++++++++++++---------\n worktree.h            | 12 ++++++++++\n 10 files changed, 96 insertions(+), 69 deletions(-)\n\nRange-diff against v1:\n1:  6cb4e0a99f ! 1:  a4894b3e15 refs: prepare `refs_init_db()` for initializing worktree refs\n    @@ refs/refs-internal.h: typedef struct ref_store *ref_store_init_fn(struct reposit\n      \t\t\t\t       struct ref_transaction *transaction,\n     \n      ## setup.c ##\n    -@@ setup.c: void create_reference_database(const char *initial_branch, int quiet)\n    - \tsafe_create_dir(git_path(\"refs\"), 1);\n    +@@ setup.c: void create_reference_database(unsigned int ref_storage_format,\n      \tadjust_shared_perm(git_path(\"refs\"));\n      \n    + \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n     -\tif (refs_init_db(&err))\n     +\tif (refs_init_db(get_main_ref_store(the_repository), 0, &err))\n      \t\tdie(\"failed to set up refs db: %s\", err.buf);\n2:  ae013eaa4a ! 2:  f500db51c2 setup: move creation of \"refs/\" into the files backend\n    @@ Commit message\n         seems a lot more sensible to have it this way round than to require\n         callers to create the directory themselves.\n     \n    +    An alternative to this would be to create \"refs/\" in `refs_init_db()`\n    +    directly. This feels conceptually unclean though as the creation of the\n    +    refdb is now cluttered across different callsites. Furthermore, both the\n    +    \"files\" and the upcoming \"reftable\" backend write backend-specific data\n    +    into the \"refs/\" directory anyway, so splitting up this logic would only\n    +    make it harder to reason about.\n    +\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## refs/files-backend.c ##\n    @@ refs/files-backend.c: static int files_init_db(struct ref_store *ref_store,\n      \n     \n      ## setup.c ##\n    -@@ setup.c: void create_reference_database(const char *initial_branch, int quiet)\n    +@@ setup.c: void create_reference_database(unsigned int ref_storage_format,\n      \tstruct strbuf err = STRBUF_INIT;\n      \tint reinit = is_reinit();\n      \n    @@ setup.c: void create_reference_database(const char *initial_branch, int quiet)\n     -\tsafe_create_dir(git_path(\"refs\"), 1);\n     -\tadjust_shared_perm(git_path(\"refs\"));\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      \t\tdie(\"failed to set up refs db: %s\", err.buf);\n    - \n3:  3cf6ceb274 ! 3:  9e99efeaa3 refs/files: skip creation of \"refs/{heads,tags}\" for worktrees\n    @@ Commit message\n     \n         The files ref backend will create both \"refs/heads\" and \"refs/tags\" in\n         the Git directory. While this logic makes sense for normal repositories,\n    -    it does not fo worktrees because those refs are \"common\" refs that would\n    -    always be contained in the main repository's ref database.\n    +    it does not for worktrees because those refs are \"common\" refs that\n    +    would always be contained in the main repository's ref database.\n     \n         Introduce a new flag telling the backend that it is expected to create a\n         per-worktree ref database and skip creation of these dirs in the files\n4:  1a6337fc51 = 4:  f2eb020288 builtin/worktree: move setup of commondir file earlier\n5:  f344a915e9 ! 5:  5525a9f9c2 worktree: expose interface to look up worktree by name\n    @@ worktree.c\n      \tfree (worktrees);\n      }\n      \n    -@@ worktree.c: static struct worktree *get_main_worktree(void)\n    +@@ worktree.c: static struct worktree *get_main_worktree(int skip_reading_head)\n      \treturn worktree;\n      }\n      \n    --static struct worktree *get_linked_worktree(const char *id)\n    -+struct worktree *get_linked_worktree(const char *id)\n    +-static struct worktree *get_linked_worktree(const char *id,\n    +-\t\t\t\t\t    int skip_reading_head)\n    ++struct worktree *get_linked_worktree(const char *id,\n    ++\t\t\t\t     int skip_reading_head)\n      {\n      \tstruct worktree *worktree = NULL;\n      \tstruct strbuf path = STRBUF_INIT;\n    @@ worktree.h: struct worktree *find_worktree(struct worktree **list,\n     + * Look up the worktree corresponding to `id`, or NULL of no such worktree\n     + * exists.\n     + */\n    -+struct worktree *get_linked_worktree(const char *id);\n    ++struct worktree *get_linked_worktree(const char *id,\n    ++\t\t\t\t     int skip_reading_head);\n     +\n      /*\n       * Return the worktree corresponding to `path`, or NULL if no such worktree\n6:  aae969301f ! 6:  240dc40de1 builtin/worktree: create refdb via ref backend\n    @@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam\n     -\tstrbuf_reset(&sb);\n     -\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n     -\twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n    -+\twt = get_linked_worktree(name);\n    ++\twt = get_linked_worktree(name, 1);\n     +\tif (!wt) {\n     +\t\tret = error(_(\"could not find created worktree '%s'\"), name);\n     +\t\tgoto done;\n\nbase-commit: 1b2234079b24da99dd78e4ce4bfe338a2a841aed\n-- \n2.43.GIT\n\n"},{"id":"486386","messageId":"a4894b3e156617c4350ab2f8d794ab32039d3fab.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 1/6] refs: prepare `refs_init_db()` for initializing worktree refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:26Z","receivedAt":"2024-01-08T10:05:30Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The purpose of `refs_init_db()` is to initialize the on-disk files of a\nnew ref database. The function is quite inflexible right now though, as\ncallers can neither specify the `struct ref_store` nor can they pass any\nflags.\n\nRefactor the interface to accept both of these. This will be required so\nthat we can start initializing per-worktree ref databases via the ref\nbackend instead of open-coding the initialization in \"worktree.c\".\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.c                | 6 ++----\n refs.h                | 2 +-\n refs/debug.c          | 4 ++--\n refs/files-backend.c  | 4 +++-\n refs/packed-backend.c | 1 +\n refs/refs-internal.h  | 4 +++-\n setup.c               | 2 +-\n 7 files changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex fdbf5f4cb1..254272ba6f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1944,11 +1944,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,\n }\n \n /* backend functions */\n-int refs_init_db(struct strbuf *err)\n+int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)\n {\n-\tstruct ref_store *refs = get_main_ref_store(the_repository);\n-\n-\treturn refs->be->init_db(refs, err);\n+\treturn refs->be->init_db(refs, flags, err);\n }\n \n const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\ndiff --git a/refs.h b/refs.h\nindex 916b874ae3..114caa272a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -126,7 +126,7 @@ int should_autocreate_reflog(const char *refname);\n \n int is_branch(const char *refname);\n \n-int refs_init_db(struct strbuf *err);\n+int refs_init_db(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 b9775f2c37..634681ca44 100644\n--- a/refs/debug.c\n+++ b/refs/debug.c\n@@ -33,10 +33,10 @@ 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, struct strbuf *err)\n+static int debug_init_db(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, err);\n+\tint res = drefs->refs->be->init_db(drefs->refs, flags, err);\n \ttrace_printf_key(&trace_refs, \"init_db: %d\\n\", res);\n \treturn res;\n }\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 43fd0ac760..153efe6662 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3220,7 +3220,9 @@ 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, struct strbuf *err UNUSED)\n+static int files_init_db(struct ref_store *ref_store,\n+\t\t\t int flags UNUSED,\n+\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\");\ndiff --git a/refs/packed-backend.c b/refs/packed-backend.c\nindex 8d1090e284..217f052d34 100644\n--- a/refs/packed-backend.c\n+++ b/refs/packed-backend.c\n@@ -1246,6 +1246,7 @@ 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 {\n \t/* Nothing to do. */\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 8e9f04cc67..82219829b0 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -529,7 +529,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, struct strbuf *err);\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 \n typedef int ref_transaction_prepare_fn(struct ref_store *refs,\n \t\t\t\t       struct ref_transaction *transaction,\ndiff --git a/setup.c b/setup.c\nindex 1ab1a66bcb..6c8f656f7c 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1943,7 +1943,7 @@ void create_reference_database(unsigned int ref_storage_format,\n \tadjust_shared_perm(git_path(\"refs\"));\n \n \trepo_set_ref_storage_format(the_repository, ref_storage_format);\n-\tif (refs_init_db(&err))\n+\tif (refs_init_db(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.43.GIT\n\n"},{"id":"486387","messageId":"f500db51c22276e4add904df452697c470764d0b.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 2/6] setup: move creation of \"refs/\" into the files backend","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:30Z","receivedAt":"2024-01-08T10:05:34Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When creating the ref database we unconditionally create the \"refs/\"\ndirectory in \"setup.c\". This is a mandatory prerequisite for all Git\nrepositories regardless of the ref backend in use, because Git will be\nunable to detect the directory as a repository if \"refs/\" doesn't exist.\n\nWe are about to add another new caller that will want to create a ref\ndatabase when creating worktrees. We would require the same logic to\ncreate the \"refs/\" directory even though the caller really should not\ncare about such low-level details. Ideally, the ref database should be\nfully initialized after calling `refs_init_db()`.\n\nMove the code to create the directory into the files backend itself to\nmake it so. This means that future ref backends will also need to have\nequivalent logic around to ensure that the directory exists, but it\nseems a lot more sensible to have it this way round than to require\ncallers to create the directory themselves.\n\nAn alternative to this would be to create \"refs/\" in `refs_init_db()`\ndirectly. This feels conceptually unclean though as the creation of the\nrefdb is now cluttered across different callsites. Furthermore, both the\n\"files\" and the upcoming \"reftable\" backend write backend-specific data\ninto the \"refs/\" directory anyway, so splitting up this logic would only\nmake it harder to reason about.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs/files-backend.c | 17 +++++++++++++++++\n setup.c              | 15 ---------------\n 2 files changed, 17 insertions(+), 15 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 153efe6662..054ecdbca3 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3228,9 +3228,26 @@ static int files_init_db(struct ref_store *ref_store,\n \t\tfiles_downcast(ref_store, REF_STORE_WRITE, \"init_db\");\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\t/*\n+\t * We need to create a \"refs\" dir in any case so that older versions of\n+\t * Git can tell that this is a repository. This serves two main purposes:\n+\t *\n+\t * - Clients will know to stop walking the parent-directory chain when\n+\t *   detecting the Git repository. Otherwise they may end up detecting\n+\t *   a Git repository in a parent directory instead.\n+\t *\n+\t * - Instead of failing to detect a repository with unknown reference\n+\t *   format altogether, old clients will print an error saying that\n+\t *   they do not understand the reference format extension.\n+\t */\n+\tstrbuf_addf(&sb, \"%s/refs\", ref_store->gitdir);\n+\tsafe_create_dir(sb.buf, 1);\n+\tadjust_shared_perm(sb.buf);\n+\n \t/*\n \t * Create .git/refs/{heads,tags}\n \t */\n+\tstrbuf_reset(&sb);\n \tfiles_ref_path(refs, &sb, \"refs/heads\");\n \tsafe_create_dir(sb.buf, 1);\n \ndiff --git a/setup.c b/setup.c\nindex 6c8f656f7c..abb271e017 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1927,21 +1927,6 @@ void create_reference_database(unsigned int ref_storage_format,\n \tstruct strbuf err = STRBUF_INIT;\n \tint reinit = is_reinit();\n \n-\t/*\n-\t * We need to create a \"refs\" dir in any case so that older versions of\n-\t * Git can tell that this is a repository. This serves two main purposes:\n-\t *\n-\t * - Clients will know to stop walking the parent-directory chain when\n-\t *   detecting the Git repository. Otherwise they may end up detecting\n-\t *   a Git repository in a parent directory instead.\n-\t *\n-\t * - Instead of failing to detect a repository with unknown reference\n-\t *   format altogether, old clients will print an error saying that\n-\t *   they do not understand the reference format extension.\n-\t */\n-\tsafe_create_dir(git_path(\"refs\"), 1);\n-\tadjust_shared_perm(git_path(\"refs\"));\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 \t\tdie(\"failed to set up refs db: %s\", err.buf);\n-- \n2.43.GIT\n\n"},{"id":"486388","messageId":"9e99efeaa384286a51a34993fa47f5c42bd81fa0.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 3/6] refs/files: skip creation of \"refs/{heads,tags}\" for worktrees","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:35Z","receivedAt":"2024-01-08T10:05:38Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The files ref backend will create both \"refs/heads\" and \"refs/tags\" in\nthe Git directory. While this logic makes sense for normal repositories,\nit does not for worktrees because those refs are \"common\" refs that\nwould always be contained in the main repository's ref database.\n\nIntroduce a new flag telling the backend that it is expected to create a\nper-worktree ref database and skip creation of these dirs in the files\nbackend when the flag is set. No other backends (currently) need\nworktree-specific logic, so this is the only required change to start\ncreating per-worktree ref databases via `refs_init_db()`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n refs.h               |  2 ++\n refs/files-backend.c | 22 ++++++++++++++--------\n 2 files changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex 114caa272a..c2dfe451a1 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -126,6 +126,8 @@ 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+\n int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);\n \n /*\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 054ecdbca3..6dae37e351 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3221,7 +3221,7 @@ static int files_reflog_expire(struct ref_store *ref_store,\n }\n \n static int files_init_db(struct ref_store *ref_store,\n-\t\t\t int flags UNUSED,\n+\t\t\t int flags,\n \t\t\t struct strbuf *err UNUSED)\n {\n \tstruct files_ref_store *refs =\n@@ -3245,15 +3245,21 @@ static int files_init_db(struct ref_store *ref_store,\n \tadjust_shared_perm(sb.buf);\n \n \t/*\n-\t * Create .git/refs/{heads,tags}\n+\t * There is no need to create directories for common refs when creating\n+\t * a worktree ref store.\n \t */\n-\tstrbuf_reset(&sb);\n-\tfiles_ref_path(refs, &sb, \"refs/heads\");\n-\tsafe_create_dir(sb.buf, 1);\n+\tif (!(flags & REFS_INIT_DB_IS_WORKTREE)) {\n+\t\t/*\n+\t\t * Create .git/refs/{heads,tags}\n+\t\t */\n+\t\tstrbuf_reset(&sb);\n+\t\tfiles_ref_path(refs, &sb, \"refs/heads\");\n+\t\tsafe_create_dir(sb.buf, 1);\n \n-\tstrbuf_reset(&sb);\n-\tfiles_ref_path(refs, &sb, \"refs/tags\");\n-\tsafe_create_dir(sb.buf, 1);\n+\t\tstrbuf_reset(&sb);\n+\t\tfiles_ref_path(refs, &sb, \"refs/tags\");\n+\t\tsafe_create_dir(sb.buf, 1);\n+\t}\n \n \tstrbuf_release(&sb);\n \treturn 0;\n-- \n2.43.GIT\n\n"},{"id":"486389","messageId":"f2eb02028840fb791b038550d6af7fba3ff49731.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 4/6] builtin/worktree: move setup of commondir file earlier","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:39Z","receivedAt":"2024-01-08T10:05:42Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Shuffle around how we create supporting worktree files so that we first\nensure that the worktree has all link files (\"gitdir\", \"commondir\")\nbefore we try to initialize the ref database by writing \"HEAD\". This\nwill be required by a subsequent commit where we start to initialize the\nref database via `refs_init_db()`, which will require an initialized\n`struct worktree *`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/worktree.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 4ac1621541..58937a2a68 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -495,6 +495,10 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_realpath(&realpath, get_git_common_dir(), 1);\n \twrite_file(sb_git.buf, \"gitdir: %s/worktrees/%s\",\n \t\t   realpath.buf, name);\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n+\twrite_file(sb.buf, \"../..\");\n+\n \t/*\n \t * This is to keep resolve_ref() happy. We need a valid HEAD\n \t * or is_git_directory() will reject the directory. Any value which\n@@ -505,9 +509,6 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n \twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n-\twrite_file(sb.buf, \"../..\");\n \n \t/*\n \t * If the current worktree has sparse-checkout enabled, then copy\n-- \n2.43.GIT\n\n"},{"id":"486390","messageId":"5525a9f9c2dbc424ef5ba4f766eb6143185bfe5d.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 5/6] worktree: expose interface to look up worktree by name","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:43Z","receivedAt":"2024-01-08T10:05:47Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Our worktree interfaces do not provide a way to look up a worktree by\nits name. Expose `get_linked_worktree()` to allow for this usecase. As\ncallers are responsible for freeing this worktree, introduce a new\nfunction `free_worktree()` that does so.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n worktree.c | 27 ++++++++++++++++-----------\n worktree.h | 12 ++++++++++++\n 2 files changed, 28 insertions(+), 11 deletions(-)\n\ndiff --git a/worktree.c b/worktree.c\nindex cc34a3419b..5d5dd46609 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -12,18 +12,23 @@\n #include \"wt-status.h\"\n #include \"config.h\"\n \n+void free_worktree(struct worktree *worktree)\n+{\n+\tif (!worktree)\n+\t\treturn;\n+\tfree(worktree->path);\n+\tfree(worktree->id);\n+\tfree(worktree->head_ref);\n+\tfree(worktree->lock_reason);\n+\tfree(worktree->prune_reason);\n+\tfree(worktree);\n+}\n+\n void free_worktrees(struct worktree **worktrees)\n {\n \tint i = 0;\n-\n-\tfor (i = 0; worktrees[i]; i++) {\n-\t\tfree(worktrees[i]->path);\n-\t\tfree(worktrees[i]->id);\n-\t\tfree(worktrees[i]->head_ref);\n-\t\tfree(worktrees[i]->lock_reason);\n-\t\tfree(worktrees[i]->prune_reason);\n-\t\tfree(worktrees[i]);\n-\t}\n+\tfor (i = 0; worktrees[i]; i++)\n+\t\tfree_worktree(worktrees[i]);\n \tfree (worktrees);\n }\n \n@@ -75,8 +80,8 @@ static struct worktree *get_main_worktree(int skip_reading_head)\n \treturn worktree;\n }\n \n-static struct worktree *get_linked_worktree(const char *id,\n-\t\t\t\t\t    int skip_reading_head)\n+struct worktree *get_linked_worktree(const char *id,\n+\t\t\t\t     int skip_reading_head)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\ndiff --git a/worktree.h b/worktree.h\nindex ce45b66de9..f14784a2ff 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -57,6 +57,13 @@ struct worktree *find_worktree(struct worktree **list,\n \t\t\t       const char *prefix,\n \t\t\t       const char *arg);\n \n+/*\n+ * Look up the worktree corresponding to `id`, or NULL of no such worktree\n+ * exists.\n+ */\n+struct worktree *get_linked_worktree(const char *id,\n+\t\t\t\t     int skip_reading_head);\n+\n /*\n  * Return the worktree corresponding to `path`, or NULL if no such worktree\n  * exists.\n@@ -134,6 +141,11 @@ void repair_worktrees(worktree_repair_fn, void *cb_data);\n  */\n void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);\n \n+/*\n+ * Free up the memory for a worktree.\n+ */\n+void free_worktree(struct worktree *);\n+\n /*\n  * Free up the memory for worktree(s)\n  */\n-- \n2.43.GIT\n\n"},{"id":"486391","messageId":"240dc40de18a79c45192466289c4e1d85d90e901.1704705733.git.ps@pks.im","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"[PATCH v2 6/6] builtin/worktree: create refdb via ref backend","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-08T10:05:47Z","receivedAt":"2024-01-08T10:05:51Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When creating a worktree we create the worktree's ref database manually\nby first writing a \"HEAD\" file so that the directory is recognized as a\nGit repository by other commands, and then running git-update-ref(1) or\ngit-symbolic-ref(1) to write the actual value. But while this is fine\nfor the files backend, this logic simply assumes too much about how the\nref backend works and will leave behind an invalid ref database once any\nother ref backend lands.\n\nRefactor the code to instead use `refs_init_db()` to initialize the ref\ndatabase so that git-worktree(1) itself does not need to know about how\nto initialize it. This will allow future ref backends to customize how\nthe per-worktree ref database is set up. Furthermore, as we now already\nhave a worktree ref store around, we can also avoid spawning external\ncommands to write the HEAD reference and instead use the refs API to do\nso.\n\nNote that we do not have an equivalent to passing the `--quiet` flag to\ngit-symbolic-ref(1) as we did before. This flag does not have an effect\nanyway though, as git-symbolic-ref(1) only honors it when reading a\nsymref, but never when writing one.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/worktree.c | 48 +++++++++++++++++++++-------------------------\n 1 file changed, 22 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 58937a2a68..dd10446d81 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -416,7 +416,6 @@ static int add_worktree(const char *path, const char *refname,\n \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n \tstruct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;\n \tconst char *name;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strvec child_env = STRVEC_INIT;\n \tunsigned int counter = 0;\n \tint len, ret;\n@@ -424,7 +423,8 @@ static int add_worktree(const char *path, const char *refname,\n \tstruct commit *commit = NULL;\n \tint is_branch = 0;\n \tstruct strbuf sb_name = STRBUF_INIT;\n-\tstruct worktree **worktrees;\n+\tstruct worktree **worktrees, *wt = NULL;\n+\tstruct ref_store *wt_refs;\n \n \tworktrees = get_worktrees();\n \tcheck_candidate_path(path, opts->force, worktrees, \"add\");\n@@ -500,15 +500,26 @@ static int add_worktree(const char *path, const char *refname,\n \twrite_file(sb.buf, \"../..\");\n \n \t/*\n-\t * This is to keep resolve_ref() happy. We need a valid HEAD\n-\t * or is_git_directory() will reject the directory. Any value which\n-\t * looks like an object ID will do since it will be immediately\n-\t * replaced by the symbolic-ref or update-ref invocation in the new\n-\t * worktree.\n+\t * Set up the ref store of the worktree and create the HEAD reference.\n \t */\n-\tstrbuf_reset(&sb);\n-\tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n-\twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n+\twt = get_linked_worktree(name, 1);\n+\tif (!wt) {\n+\t\tret = error(_(\"could not find created worktree '%s'\"), name);\n+\t\tgoto done;\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+\tif (ret)\n+\t\tgoto done;\n+\n+\tif (!is_branch && commit)\n+\t\tret = refs_update_ref(wt_refs, NULL, \"HEAD\", &commit->object.oid,\n+\t\t\t\t      NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\telse\n+\t\tret = refs_create_symref(wt_refs, \"HEAD\", symref.buf, NULL);\n+\tif (ret)\n+\t\tgoto done;\n \n \t/*\n \t * If the current worktree has sparse-checkout enabled, then copy\n@@ -527,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,\n \n \tstrvec_pushf(&child_env, \"%s=%s\", GIT_DIR_ENVIRONMENT, sb_git.buf);\n \tstrvec_pushf(&child_env, \"%s=%s\", GIT_WORK_TREE_ENVIRONMENT, path);\n-\tcp.git_cmd = 1;\n-\n-\tif (!is_branch && commit) {\n-\t\tstrvec_pushl(&cp.args, \"update-ref\", \"HEAD\",\n-\t\t\t     oid_to_hex(&commit->object.oid), NULL);\n-\t} else {\n-\t\tstrvec_pushl(&cp.args, \"symbolic-ref\", \"HEAD\",\n-\t\t\t     symref.buf, NULL);\n-\t\tif (opts->quiet)\n-\t\t\tstrvec_push(&cp.args, \"--quiet\");\n-\t}\n-\n-\tstrvec_pushv(&cp.env, child_env.v);\n-\tret = run_command(&cp);\n-\tif (ret)\n-\t\tgoto done;\n \n \tif (opts->orphan &&\n \t    (ret = make_worktree_orphan(refname, opts, &child_env)))\n@@ -588,6 +583,7 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_release(&sb_git);\n \tstrbuf_release(&sb_name);\n \tstrbuf_release(&realpath);\n+\tfree_worktree(wt);\n \treturn ret;\n }\n \n-- \n2.43.GIT\n\n"},{"id":"486825","messageId":"CAOLa=ZS3aVP=h9iC2i_4Hbx_-OSdqJ8S6xYT65CPyXd+9_=4Nw@mail.gmail.com","threadId":"60666","inReplyTo":"cover.1704705733.git.ps@pks.im","subject":"Re: [PATCH v2 0/6] worktree: initialize refdb via ref backends","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-16T09:17:40Z","receivedAt":"2024-01-16T09:17:42Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Hi,\n>\n> this is the second version of my patch series that refactors the\n> initialization of worktree refdbs to use the refs API.\n>\n> Changes compared to v1:\n>\n>   - Improved commit messages.\n>\n>   - This series is now based on `ps/refstorage-extension`, 1b2234079b\n>     (t9500: write \"extensions.refstorage\" into config, 2023-12-29).\n>     While there is no functional dependency between those series,\n>     merging both topics causes a merge conflict.\n>\n\nThis looks good to me now. Thanks Patrick!\n"},{"id":"486854","messageId":"xmqqa5p517x9.fsf@gitster.g","threadId":"60666","inReplyTo":"CAOLa=ZS3aVP=h9iC2i_4Hbx_-OSdqJ8S6xYT65CPyXd+9_=4Nw@mail.gmail.com","subject":"Re: [PATCH v2 0/6] worktree: initialize refdb via ref backends","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-16T17:53:38Z","receivedAt":"2024-01-16T17:53:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Patrick Steinhardt <ps@pks.im> writes:\n>\n>> Hi,\n>>\n>> this is the second version of my patch series that refactors the\n>> initialization of worktree refdbs to use the refs API.\n>>\n>> Changes compared to v1:\n>>\n>>   - Improved commit messages.\n>>\n>>   - This series is now based on `ps/refstorage-extension`, 1b2234079b\n>>     (t9500: write \"extensions.refstorage\" into config, 2023-12-29).\n>>     While there is no functional dependency between those series,\n>>     merging both topics causes a merge conflict.\n>>\n>\n> This looks good to me now. Thanks Patrick!\n\nThanks, both.\n"}]}