From: Michael Haggerty <mhagger@alum.mit.edu>
To: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>, git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>
Subject: Re: [PATCH 2/2] worktree.c: use submodule interface to access refs from another worktree
Date: Thu, 9 Feb 2017 07:07:39 +0100 [thread overview]
Message-ID: <37fe2024-0378-a974-a28d-18a89d3e2312@alum.mit.edu> (raw)
In-Reply-To: <20170208113144.8201-3-pclouds@gmail.com>
On 02/08/2017 12:31 PM, Nguyễn Thái Ngọc Duy wrote:
> The patch itself is relatively simple: manual parsing code is replaced
> with a call to resolve_ref_submodule(). The manual parsing code must die
> because only refs/files-backend.c should do that. Why submodule here is
> a more interesting question.
>
> From an outside look, any .git/worktrees/foo is seen as a "normal"
> repository. You can set GIT_DIR to it and have access to everything,
> even shared things that are not literally inside that directory, like
> object db or shared refs.
>
> On top of that, linked worktrees point to those directories with ".git"
> files. These two make a linked worktree's path "X" a "submodule" (*) (**)
> because X/.git is a file that points to a repository somewhere.
>
> As such, we can just linked worktree's path as a submodule. We just need
> to make sure they are unique because they are used to lookup submodule
> refs store.
>
> Main worktree is a a bit trickier. If we stand at a linked worktree, we
> may still need to peek into main worktree's HEAD, for example. We can
> treat main worktree's path as submodule as well since git_path_submodule()
> can tolerate ".git" dirs, in addition to ".git" files.
>
> The constraint is, if main worktree is X, then the git repo must be at
> X/.git. If the user separates .git repo far away and tell git to point
> to it via GIT_DIR or something else, then the "main worktree as submodule"
> trick fails. Within multiple worktree context, I think we can limit
> support to "standard" layout, at least for now.
>
> (*) The differences in sharing object database and refs between
> submodules and linked worktrees don't really matter in this context.
>
> (**) At this point, we may want to rename refs *_submodule API to
> something more neutral, maybe s/_submodule/_remote/
It is unquestionably a good goal to avoid parsing references outside of
`refs/files-backend.c`. But I'm not a fan of this approach.
There are two meanings of the concept of a "ref store", and I think this
change muddles them:
1. The references that happen to be *physically* stored in a particular
location, for example the `refs/bisect/*` references in a worktree.
2. The references that *logically* should be considered part of a
particular repository. This might require stitching together
references from multiple sources, for example `HEAD` and
`refs/bisect` from a worktree's own directory with other
references from the main repository.
Either of these concepts can be implemented via the `ref_store` abstraction.
The `ref_store` for a submodule should represent the references
logically visible from the submodule. The main program shouldn't care
whether the references are stored in a single physical location or
spread across multiple locations (for example, if the submodule were
itself a linked worktree).
The `ref_store` that you want here for a worktree is not the worktree's
*logical* `ref_store`. You want the worktree's *physical* `ref_store`.
Mixing logical and physical reference stores together is a bad idea
(even if we were willing to ignore the fact that worktrees are not
submodules in the accepted sense of the word).
The point of my `submodule-hash` branch [1] was to separate these
concepts better by breaking the current 1:1 connection between
`ref_store`s and submodules. This would allow `ref_store`s to be created
for other purposes, such as to represent worktree refs. If you want the
*logical* `ref_store` for a submodule, you access it through the
`submodule_ref_stores` table. If you want the *physical* `ref_store` for
a worktree, you should access it through a different table.
I think the best solution would be to expose the concept of `ref_store`
in the public refs API. Then users of submodules would essentially do
struct ref_store *refs = get_submodule_refs(submodule_path);
... resolve_ref_recursively(refs, refname, 0, sha1, &flags) ...
... for_each_ref(refs, fn, cb_data) ...
whereas for a worktree you'd have to look up the `ref_store` instance
somewhere else (or maybe keep it as part of some worktree structure, if
there is one) but you would use it via the same API.
Michael
[1] https://github.com/mhagger/git
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> branch.c | 3 +-
> worktree.c | 99 +++++++++++++++-----------------------------------------------
> worktree.h | 2 +-
> 3 files changed, 27 insertions(+), 77 deletions(-)
>
> diff --git a/branch.c b/branch.c
> index b955d4f316..db5843718f 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -354,7 +354,8 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref)
> for (i = 0; worktrees[i]; i++) {
> if (worktrees[i]->is_detached)
> continue;
> - if (strcmp(oldref, worktrees[i]->head_ref))
> + if (worktrees[i]->head_ref &&
> + strcmp(oldref, worktrees[i]->head_ref))
> continue;
>
> if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
> diff --git a/worktree.c b/worktree.c
> index d633761575..25e5bc9a3e 100644
> --- a/worktree.c
> +++ b/worktree.c
> @@ -19,54 +19,24 @@ void free_worktrees(struct worktree **worktrees)
> free (worktrees);
> }
>
> -/*
> - * read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
> - * set is_detached to 1 (0) if the ref is detached (is not detached).
> - *
> - * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so
> - * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses
> - * git_path). Parse the ref ourselves.
> - *
> - * return -1 if the ref is not a proper ref, 0 otherwise (success)
> - */
> -static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
> -{
> - if (is_detached)
> - *is_detached = 0;
> - if (!strbuf_readlink(ref, path_to_ref, 0)) {
> - /* HEAD is symbolic link */
> - if (!starts_with(ref->buf, "refs/") ||
> - check_refname_format(ref->buf, 0))
> - return -1;
> - } else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
> - /* textual symref or detached */
> - if (!starts_with(ref->buf, "ref:")) {
> - if (is_detached)
> - *is_detached = 1;
> - } else {
> - strbuf_remove(ref, 0, strlen("ref:"));
> - strbuf_trim(ref);
> - if (check_refname_format(ref->buf, 0))
> - return -1;
> - }
> - } else
> - return -1;
> - return 0;
> -}
> -
> /**
> - * Add the head_sha1 and head_ref (if not detached) to the given worktree
> + * Update head_sha1, head_ref and is_detached of the given worktree
> */
> -static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)
> +static void add_head_info(struct worktree *wt)
> {
> - if (head_ref->len) {
> - if (worktree->is_detached) {
> - get_sha1_hex(head_ref->buf, worktree->head_sha1);
> - } else {
> - resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL);
> - worktree->head_ref = strbuf_detach(head_ref, NULL);
> - }
> - }
> + int flags;
> + const char *target;
> +
> + target = resolve_ref_submodule(wt->path, "HEAD",
> + RESOLVE_REF_READING,
> + wt->head_sha1, &flags);
> + if (!target)
> + return;
> +
> + if (flags & REF_ISSYMREF)
> + wt->head_ref = xstrdup(target);
> + else
> + wt->is_detached = 1;
> }
>
> /**
> @@ -77,9 +47,7 @@ static struct worktree *get_main_worktree(void)
> struct worktree *worktree = NULL;
> struct strbuf path = STRBUF_INIT;
> struct strbuf worktree_path = STRBUF_INIT;
> - struct strbuf head_ref = STRBUF_INIT;
> int is_bare = 0;
> - int is_detached = 0;
>
> strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
> is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
> @@ -91,13 +59,10 @@ static struct worktree *get_main_worktree(void)
> worktree = xcalloc(1, sizeof(*worktree));
> worktree->path = strbuf_detach(&worktree_path, NULL);
> worktree->is_bare = is_bare;
> - worktree->is_detached = is_detached;
> - if (!parse_ref(path.buf, &head_ref, &is_detached))
> - add_head_info(&head_ref, worktree);
> + add_head_info(worktree);
>
> strbuf_release(&path);
> strbuf_release(&worktree_path);
> - strbuf_release(&head_ref);
> return worktree;
> }
>
> @@ -106,8 +71,6 @@ static struct worktree *get_linked_worktree(const char *id)
> struct worktree *worktree = NULL;
> struct strbuf path = STRBUF_INIT;
> struct strbuf worktree_path = STRBUF_INIT;
> - struct strbuf head_ref = STRBUF_INIT;
> - int is_detached = 0;
>
> if (!id)
> die("Missing linked worktree name");
> @@ -127,19 +90,14 @@ static struct worktree *get_linked_worktree(const char *id)
> strbuf_reset(&path);
> strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
>
> - if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
> - goto done;
> -
> worktree = xcalloc(1, sizeof(*worktree));
> worktree->path = strbuf_detach(&worktree_path, NULL);
> worktree->id = xstrdup(id);
> - worktree->is_detached = is_detached;
> - add_head_info(&head_ref, worktree);
> + add_head_info(worktree);
>
> done:
> strbuf_release(&path);
> strbuf_release(&worktree_path);
> - strbuf_release(&head_ref);
> return worktree;
> }
>
> @@ -334,8 +292,6 @@ const struct worktree *find_shared_symref(const char *symref,
> const char *target)
> {
> const struct worktree *existing = NULL;
> - struct strbuf path = STRBUF_INIT;
> - struct strbuf sb = STRBUF_INIT;
> static struct worktree **worktrees;
> int i = 0;
>
> @@ -345,6 +301,10 @@ const struct worktree *find_shared_symref(const char *symref,
>
> for (i = 0; worktrees[i]; i++) {
> struct worktree *wt = worktrees[i];
> + const char *symref_target;
> + unsigned char sha1[20];
> + int flags;
> +
> if (wt->is_bare)
> continue;
>
> @@ -359,25 +319,14 @@ const struct worktree *find_shared_symref(const char *symref,
> }
> }
>
> - strbuf_reset(&path);
> - strbuf_reset(&sb);
> - strbuf_addf(&path, "%s/%s",
> - get_worktree_git_dir(wt),
> - symref);
> -
> - if (parse_ref(path.buf, &sb, NULL)) {
> - continue;
> - }
> -
> - if (!strcmp(sb.buf, target)) {
> + symref_target = resolve_ref_submodule(wt->path, symref, 0,
> + sha1, &flags);
> + if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) {
> existing = wt;
> break;
> }
> }
>
> - strbuf_release(&path);
> - strbuf_release(&sb);
> -
> return existing;
> }
>
> diff --git a/worktree.h b/worktree.h
> index 6bfb985203..5ea5e503fb 100644
> --- a/worktree.h
> +++ b/worktree.h
> @@ -4,7 +4,7 @@
> struct worktree {
> char *path;
> char *id;
> - char *head_ref;
> + char *head_ref; /* NULL if HEAD is broken or detached */
> char *lock_reason; /* internal use */
> unsigned char head_sha1[20];
> int is_detached;
>
next prev parent reply other threads:[~2017-02-09 6:07 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-02-08 11:31 [PATCH RFC 0/2] Kill manual ref parsing code in worktree.c Nguyễn Thái Ngọc Duy
2017-02-08 11:31 ` [PATCH 1/2] refs.c: add resolve_ref_submodule() Nguyễn Thái Ngọc Duy
2017-02-09 5:20 ` Michael Haggerty
2017-02-08 11:31 ` [PATCH 2/2] worktree.c: use submodule interface to access refs from another worktree Nguyễn Thái Ngọc Duy
2017-02-08 19:50 ` Stefan Beller
2017-02-08 23:19 ` Junio C Hamano
2017-02-08 23:25 ` Junio C Hamano
2017-02-09 6:07 ` Michael Haggerty [this message]
2017-02-09 6:55 ` Junio C Hamano
2017-02-09 8:04 ` Michael Haggerty
2017-02-09 11:59 ` Duy Nguyen
2017-02-09 14:03 ` Michael Haggerty
2017-02-08 18:18 ` [PATCH RFC 0/2] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-02-16 12:02 ` [PATCH v2 0/5] " Nguyễn Thái Ngọc Duy
2017-02-16 12:02 ` [PATCH v2 1/5] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-02-16 12:02 ` [PATCH v2 2/5] refs.c: add refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-02-16 12:03 ` [PATCH v2 3/5] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-02-16 12:03 ` [PATCH v2 4/5] refs: add refs_create_symref() Nguyễn Thái Ngọc Duy
2017-02-16 12:03 ` [PATCH v2 5/5] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-03-18 10:02 ` [PATCH v3 0/4] Kill manual ref parsing code in worktree.c Nguyễn Thái Ngọc Duy
2017-03-18 10:02 ` [PATCH v3 1/4] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-03-18 17:54 ` Junio C Hamano
2017-03-19 9:34 ` Duy Nguyen
2017-03-18 10:02 ` [PATCH v3 2/4] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-03-20 6:59 ` Michael Haggerty
2017-03-20 12:01 ` Duy Nguyen
2017-03-20 14:25 ` Michael Haggerty
2017-03-26 8:26 ` Duy Nguyen
2017-03-18 10:02 ` [PATCH v3 3/4] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-03-18 10:02 ` [PATCH v3 4/4] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-03-18 17:49 ` [PATCH v3 0/4] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-04-04 10:21 ` [PATCH v4 0/5] " Nguyễn Thái Ngọc Duy
2017-04-04 10:21 ` [PATCH v4 1/5] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-04-04 10:21 ` [PATCH v4 2/5] refs.c: make submodule ref store hashmap generic Nguyễn Thái Ngọc Duy
2017-04-04 10:21 ` [PATCH v4 3/5] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-04-22 4:52 ` Michael Haggerty
2017-04-04 10:21 ` [PATCH v4 4/5] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-04-04 10:21 ` [PATCH v4 5/5] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-04-14 1:40 ` [PATCH v4 0/5] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-04-14 2:02 ` Junio C Hamano
2017-04-14 12:45 ` Duy Nguyen
2017-04-17 1:36 ` Junio C Hamano
2017-04-22 5:06 ` Michael Haggerty
2017-04-24 10:01 ` [PATCH v5 0/6] " Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 1/6] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 2/6] refs.c: make submodule ref store hashmap generic Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 3/6] refs: add REFS_STORE_ALL_CAPS Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 4/6] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 5/6] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-04-24 10:01 ` [PATCH v5 6/6] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-04-25 4:30 ` [PATCH v5 0/6] Kill manual ref parsing code in worktree.c Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=37fe2024-0378-a974-a28d-18a89d3e2312@alum.mit.edu \
--to=mhagger@alum.mit.edu \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=pclouds@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).