git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Sunshine <sunshine@sunshineco.com>
To: Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Cc: Git List <git@vger.kernel.org>, Derrick Stolee <stolee@gmail.com>,
	Sean Allred <allred.sean@gmail.com>,
	Junio C Hamano <gitster@pobox.com>,
	Derrick Stolee <derrickstolee@github.com>,
	Derrick Stolee <dstolee@microsoft.com>
Subject: Re: [PATCH v2 3/5] worktree: add upgrade_to_worktree_config()
Date: Tue, 21 Dec 2021 19:45:03 -0500	[thread overview]
Message-ID: <CAPig+cQrJ9yWjkc8VMu=uyx_qtrXdL3cNnxLVafoxOo6e-r9kw@mail.gmail.com> (raw)
In-Reply-To: <ed8e2a7b19d236642b3b8d3a49d017d29753db56.1640114048.git.gitgitgadget@gmail.com>

On Tue, Dec 21, 2021 at 2:14 PM Derrick Stolee via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> Some features, such as the sparse-checkout builtin, require using the
> worktree config extension. It might seem simple to upgrade the
> repository format and add extensions.worktreeConfig, and that is what
> happens in the sparse-checkout builtin.
>
> Transitioning from one config file to multiple has some strange
> side-effects. In particular, if the base repository is bare and the
> worktree is not, Git knows to treat the worktree as non-bare as a
> special case when not using worktree config. Once worktree config is
> enabled, Git stops that special case since the core.bare setting could
> apply at the worktree config level. This opens the door for bare
> worktrees.

It would be a good idea to drop the final sentence since there is no
such thing as a bare worktree (either conceptually or practically),
and end the first sentence at "case": i.e. "... stops that special
case."

> To help resolve this transition, create upgrade_to_worktree_config() to
> navigate the intricacies of this operation. In particular, we need to
> look for core.bare=true within the base config file and move that
> setting into the core repository's config.worktree file.
>
> To gain access to the core repository's config and config.worktree file,
> we reference a repository struct's 'commondir' member. If the repository
> was a submodule instead of a worktree, then this still applies
> correctly.

I'm not sure how much this commit message is going to help someone who
did not participate in the discussion which led to this patch series.
I think the entire commit message could be written more concisely like
this:

    worktree: add helper to upgrade repository to per-worktree config

    Changing a repository to use per-worktree configuration is a
    somewhat involved manual process, as described in the
    `git-worktree` documentation, but it's easy to get wrong if the
    steps are not followed precisely, which could lead to odd
    anomalies such as Git thinking that a worktree is "bare" (which
    conceptually makes no sense). Therefore, add a utility function to
    automate the process of switching to per-worktree configuration
    for modules which require such configuration. (In the future, it
    may make sense to also expose this convenience as a `git-worktree`
    command to automate the process for end-users, as well.)

    To upgrade the repository to per-worktree configuration, it performs
    these steps:

    * enable `extensions.worktreeConfig` in .git/config

    * relocate `core.bare` from .git/config to .git/config.worktree
      (if key exists)

    * relocate `core.worktree` from .git/config to
      .git/config.worktree (if key exists)

    It also upgrades the repository format to 1 if necessary since
    that is a prerequisite of using `extensions`.

> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
> Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
> ---
> diff --git a/worktree.c b/worktree.c
> @@ -830,3 +831,49 @@ int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath,
> +int upgrade_to_worktree_config(struct repository *r)
> +{
> +       int res;
> +       int bare = 0;
> +       struct config_set cs = { 0 };

This function is doing a lot of unnecessary work if per-worktree
configuration is already enabled. The very first thing it should be
doing is checking whether or not it actually needs to do that work,
and short-circuit if it doesn't. I would think that simply checking
whether `extensions.worktreeConfig` is true and returning early if it
is would be sufficient.

> +       char *base_config_file = xstrfmt("%s/config", r->commondir);

If we look at path.c:strbuf_worktree_gitdir(), we see that this should
be using `r->gitdir`, not `r->commondir`.

> +       char *base_worktree_file = xstrfmt("%s/config.worktree", r->commondir);

Per path.c:strbuf_worktree_gitdir(), this use of `r->commondir` is
correct. Good.

Can we use more meaningful variable names? It's not at all clear what
"base" means in this context (I don't think it has any analog in Git
terminology). Perhaps name these `shared_config` and `repo_config`,
respectively.

> +       git_configset_init(&cs);
> +       git_configset_add_file(&cs, base_config_file);
> +
> +       /*
> +        * If the base repository is bare, then we need to move core.bare=true
> +        * out of the base config file and into the base repository's
> +        * config.worktree file.
> +        */

Here, too, it's not clear what "base" means. I think you want to say
that it needs to "move `core.bare` from the shared config to the
repo-specific config".

> +       if (!git_configset_get_bool(&cs, "core.bare", &bare) && bare) {
> +               if ((res = git_config_set_in_file_gently(base_worktree_file,
> +                                                       "core.bare", "true"))) {
> +                       error(_("unable to set core.bare=true in '%s'"), base_worktree_file);
> +                       goto cleanup;
> +               }
> +
> +               if ((res = git_config_set_in_file_gently(base_config_file,
> +                                                       "core.bare", NULL))) {
> +                       error(_("unable to unset core.bare=true in '%s'"), base_config_file);
> +                       goto cleanup;
> +               }
> +       }

This seems unnecessarily complicated and overly specific, thus
potentially confusing. The requirements laid out in git-worktree.txt
say only to move the configuration key from .git/config to
.git/config.worktree; it doesn't add any qualifiers about the value
being "true". And, indeed, we should not care about the value; it's
immaterial to this operation. Instead, we should just treat it
opaquely and relocate the key and value from .git/config (if it
exists) to .git/config.worktree without interpretation.

The error messages are too specific, as well, by mentioning "true".
They could instead be:

    unable to set `core.bare` in '%s'

and

    unable to remove `core.bare` from '%s'

However, there is a much more _severe_ problem with this
implementation: it is incomplete. As documented in git-worktree.txt
(and mentioned several times during this discussion), this utility
function _must_ relocate both `core.bare` _and_ `core.worktree` (if
they exist) from .git/config to .git/config.worktree. This
implementation neglects to relocate `core.worktree`, which can leave
things in quite a broken state (just as neglecting to relocate
`core.bare` can).

> +       if (upgrade_repository_format(r, 1) < 0) {
> +               res = error(_("unable to upgrade repository format to enable worktreeConfig"));
> +               goto cleanup;
> +       }
> +       if ((res = git_config_set_gently("extensions.worktreeConfig", "true"))) {
> +               error(_("failed to set extensions.worktreeConfig setting"));
> +               goto cleanup;
> +       }

The order in which this function performs its operations can leave the
repository in a broken state if any of the steps fails. For instance,
if setting `extensions.worktreeConfig=true` fails _after_ you've
relocated `core.bare` (and `core.worktree`) to .git/config.worktree,
then those configuration values will no longer be "active" since the
config system won't consult .git/config.worktree without
`extensions.worktreeConfig` enabled.

To be resilient against this sort of problem, you should perform the
operations in this order:

(1) upgrade repository format to 1
(2) enable `extensions.worktreeConfig`
(3) relocate `core.bare` and `core.worktree`

> +cleanup:
> +       git_configset_clear(&cs);
> +       free(base_config_file);
> +       free(base_worktree_file);
> +       trace2_printf("returning %d", res);

Is this leftover debugging or intentional?

> +       return res;
> +}
> diff --git a/worktree.h b/worktree.h
> @@ -182,4 +182,16 @@ void strbuf_worktree_ref(const struct worktree *wt,
> +/**
> + * Upgrade the config of the current repository and its base (if different
> + * from this repository) to use worktree-config. This might adjust config
> + * in both repositories, including:

Here, too, it's not clear what "base" means. Moreover, this seems to
be talking about multiple repositories, but we're only dealing with a
single repository and zero or more worktrees, so it's not clear what
this is trying to say.

> + * 1. Upgrading the repository format version to 1.
> + * 2. Adding extensions.worktreeConfig to the base config file.
> + * 3. Moving core.bare=true from the base config file to the base
> + *    repository's config.worktree file.

As mentioned above, it's unnecessary and perhaps confusing to focus
only on "true" here; we should be treating the value opaquely.

Also, if you're talking about the specific config settings which this
relocates, then `core.worktree` should be mentioned too, not just
`core.bare`.

> + */
> +int upgrade_to_worktree_config(struct repository *r);

  reply	other threads:[~2021-12-22  0:45 UTC|newest]

Thread overview: 138+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-20 15:57 [PATCH 0/4] Sparse checkout: fix bug with worktree of bare repo Derrick Stolee via GitGitGadget
2021-12-20 15:57 ` [PATCH 1/4] setup: use a repository when upgrading format Derrick Stolee via GitGitGadget
2021-12-20 15:57 ` [PATCH 2/4] config: make some helpers repo-aware Derrick Stolee via GitGitGadget
2021-12-20 15:57 ` [PATCH 3/4] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-20 17:32   ` Derrick Stolee
2021-12-21  0:01     ` Eric Sunshine
2021-12-21  5:59       ` Eric Sunshine
2021-12-21 13:41       ` Derrick Stolee
2021-12-21  5:53   ` Eric Sunshine
2021-12-21 13:45     ` Derrick Stolee
2021-12-21 23:29       ` Eric Sunshine
2021-12-20 15:57 ` [PATCH 4/4] sparse-checkout: use repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-20 16:21 ` [PATCH 0/4] Sparse checkout: fix bug with worktree of bare repo Eric Sunshine
2021-12-20 17:34   ` Derrick Stolee
2021-12-21  6:10     ` Eric Sunshine
2021-12-21 19:14 ` [PATCH v2 0/5] " Derrick Stolee via GitGitGadget
2021-12-21 19:14   ` [PATCH v2 1/5] setup: use a repository when upgrading format Derrick Stolee via GitGitGadget
2021-12-21 19:14   ` [PATCH v2 2/5] config: make some helpers repo-aware Derrick Stolee via GitGitGadget
2021-12-21 19:14   ` [PATCH v2 3/5] worktree: add upgrade_to_worktree_config() Derrick Stolee via GitGitGadget
2021-12-22  0:45     ` Eric Sunshine [this message]
2021-12-28 15:03       ` Derrick Stolee
2021-12-28 16:58         ` Eric Sunshine
2021-12-28 17:03           ` Derrick Stolee
2021-12-22  5:38     ` Junio C Hamano
2021-12-28 15:13       ` Derrick Stolee
2021-12-21 19:14   ` [PATCH v2 4/5] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-22  1:11     ` Eric Sunshine
2021-12-21 19:14   ` [PATCH v2 5/5] sparse-checkout: use repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-22  5:48     ` Eric Sunshine
2021-12-22  6:05   ` [PATCH v2 0/5] Sparse checkout: fix bug with worktree of bare repo Eric Sunshine
2021-12-22 22:54   ` Elijah Newren
2021-12-27  7:15     ` Eric Sunshine
2021-12-27  7:34       ` Eric Sunshine
2021-12-27 20:16         ` Elijah Newren
2021-12-28  9:11           ` Eric Sunshine
2021-12-30  6:21           ` Eric Sunshine
2021-12-30 17:40             ` Elijah Newren
2021-12-27 19:35       ` Elijah Newren
2021-12-28  7:33         ` Eric Sunshine
2021-12-28 18:16           ` Elijah Newren
2021-12-30  6:40             ` Eric Sunshine
2021-12-30 18:38               ` Elijah Newren
2022-01-03  6:51                 ` Eric Sunshine
2021-12-28 21:32   ` [PATCH v3 0/6] " Derrick Stolee via GitGitGadget
2021-12-28 21:32     ` [PATCH v3 1/6] setup: use a repository when upgrading format Derrick Stolee via GitGitGadget
2021-12-28 21:32     ` [PATCH v3 2/6] config: make some helpers repo-aware Derrick Stolee via GitGitGadget
2021-12-28 21:32     ` [PATCH v3 3/6] worktree: add 'init-worktree-config' subcommand Derrick Stolee via GitGitGadget
2021-12-29  6:48       ` Eric Sunshine
2021-12-30  8:41       ` Eric Sunshine
2021-12-30 17:29         ` Derrick Stolee
2022-01-03  6:38           ` Eric Sunshine
2021-12-28 21:32     ` [PATCH v3 4/6] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-28 21:32     ` [PATCH v3 5/6] sparse-checkout: use repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2021-12-30  9:01       ` Eric Sunshine
2021-12-28 21:32     ` [PATCH v3 6/6] worktree: copy sparse-checkout patterns and config on add Derrick Stolee via GitGitGadget
2021-12-29  6:37       ` Eric Sunshine
2021-12-29 17:31         ` Derrick Stolee
2021-12-29 19:51           ` Elijah Newren
2021-12-29 21:39             ` Derrick Stolee
2021-12-29 22:45               ` Elijah Newren
2021-12-30  8:16                 ` Eric Sunshine
2021-12-30  8:01             ` Eric Sunshine
2021-12-29  9:39     ` [PATCH v3 0/6] Sparse checkout: fix bug with worktree of bare repo Elijah Newren
2021-12-29 17:38       ` Derrick Stolee
2021-12-30  7:41         ` Eric Sunshine
2021-12-30  7:40       ` Eric Sunshine
2021-12-30 17:41         ` Derrick Stolee
2021-12-30 19:29           ` Elijah Newren
2022-01-03  7:11             ` Eric Sunshine
2021-12-30 18:46         ` Elijah Newren
2022-01-25 18:42     ` [PATCH v4 0/5] " Derrick Stolee via GitGitGadget
2022-01-25 18:42       ` [PATCH v4 1/5] Documentation: add extensions.worktreeConfig details Derrick Stolee via GitGitGadget
2022-01-26  6:59         ` Bagas Sanjaya
2022-01-27 14:15           ` Derrick Stolee
2022-01-27  6:43         ` Elijah Newren
2022-01-27 14:17           ` Derrick Stolee
2022-01-25 18:42       ` [PATCH v4 2/5] worktree: create init_worktree_config() Derrick Stolee via GitGitGadget
2022-01-27  7:01         ` Elijah Newren
2022-01-25 18:42       ` [PATCH v4 3/5] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2022-01-25 18:42       ` [PATCH v4 4/5] sparse-checkout: set worktree-config correctly Derrick Stolee via GitGitGadget
2022-01-27  7:15         ` Elijah Newren
2022-01-27 14:24           ` Derrick Stolee
2022-01-25 18:42       ` [PATCH v4 5/5] worktree: copy sparse-checkout patterns and config on add Derrick Stolee via GitGitGadget
2022-01-27  7:09         ` Elijah Newren
2022-01-27  7:20       ` [PATCH v4 0/5] Sparse checkout: fix bug with worktree of bare repo Elijah Newren
2022-01-27 14:29         ` Derrick Stolee
2022-01-31 15:00       ` [PATCH v5 " Derrick Stolee via GitGitGadget
2022-01-31 15:00         ` [PATCH v5 1/5] Documentation: add extensions.worktreeConfig details Derrick Stolee via GitGitGadget
2022-02-06  9:17           ` Eric Sunshine
2022-01-31 15:00         ` [PATCH v5 2/5] worktree: create init_worktree_config() Derrick Stolee via GitGitGadget
2022-02-06  9:32           ` Eric Sunshine
2022-01-31 15:00         ` [PATCH v5 3/5] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2022-01-31 15:00         ` [PATCH v5 4/5] sparse-checkout: set worktree-config correctly Derrick Stolee via GitGitGadget
2022-02-06 10:21           ` Eric Sunshine
2022-01-31 15:00         ` [PATCH v5 5/5] worktree: copy sparse-checkout patterns and config on add Derrick Stolee via GitGitGadget
2022-02-06 10:36           ` Jean-Noël AVILA
2022-02-07 14:10             ` Derrick Stolee
2022-02-09  7:53               ` Jean-Noël Avila
2022-02-09 14:45                 ` Derrick Stolee
2022-02-06 11:30           ` Eric Sunshine
2022-02-06 19:36             ` Eric Sunshine
2022-02-07 14:30             ` Derrick Stolee
2022-02-15 22:01               ` Eric Sunshine
2022-02-16 13:58                 ` Derrick Stolee
2022-01-31 16:17         ` [PATCH v5 0/5] Sparse checkout: fix bug with worktree of bare repo Elijah Newren
2022-02-07 21:32         ` [PATCH v6 0/6] " Derrick Stolee via GitGitGadget
2022-02-07 21:32           ` [PATCH v6 1/6] Documentation: add extensions.worktreeConfig details Derrick Stolee via GitGitGadget
2022-02-08 22:20             ` Junio C Hamano
2022-02-09  2:34               ` Derrick Stolee
2022-02-09 17:19                 ` Junio C Hamano
2022-02-09 17:26                   ` Derrick Stolee
2022-02-09 17:51                   ` Elijah Newren
2022-02-09 18:40                     ` Junio C Hamano
2022-02-15 20:37                 ` Eric Sunshine
2022-02-16  1:51                   ` Junio C Hamano
2022-02-09 18:04               ` Elijah Newren
2022-02-09 18:41                 ` Junio C Hamano
2022-02-07 21:32           ` [PATCH v6 2/6] worktree: create init_worktree_config() Derrick Stolee via GitGitGadget
2022-02-08 22:09             ` Junio C Hamano
2022-02-09  2:21               ` Derrick Stolee
2022-02-09 17:34                 ` Junio C Hamano
2022-02-09 16:43               ` Elijah Newren
2022-02-07 21:33           ` [PATCH v6 3/6] config: add repo_config_set_worktree_gently() Derrick Stolee via GitGitGadget
2022-02-08 22:18             ` Junio C Hamano
2022-02-09  2:27               ` Derrick Stolee
2022-02-09 17:49                 ` Junio C Hamano
2022-02-10 14:48                   ` Derrick Stolee
2022-02-10 16:45                     ` Junio C Hamano
2022-02-07 21:33           ` [PATCH v6 4/6] sparse-checkout: set worktree-config correctly Derrick Stolee via GitGitGadget
2022-02-07 21:33           ` [PATCH v6 5/6] worktree: copy sparse-checkout patterns and config on add Derrick Stolee via GitGitGadget
2022-02-15 22:23             ` Eric Sunshine
2022-02-07 21:33           ` [PATCH v6 6/6] config: make git_configset_get_string_tmp() private Derrick Stolee via GitGitGadget
2022-02-08  4:14           ` [PATCH v6 0/6] Sparse checkout: fix bug with worktree of bare repo Elijah Newren
2022-02-08  5:02             ` Eric Sunshine
2022-02-08  5:18               ` Elijah Newren
2022-02-08  5:42                 ` Eric Sunshine
2022-02-16  0:56                   ` Eric Sunshine
2022-02-08 14:33               ` Derrick Stolee

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='CAPig+cQrJ9yWjkc8VMu=uyx_qtrXdL3cNnxLVafoxOo6e-r9kw@mail.gmail.com' \
    --to=sunshine@sunshineco.com \
    --cc=allred.sean@gmail.com \
    --cc=derrickstolee@github.com \
    --cc=dstolee@microsoft.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=gitster@pobox.com \
    --cc=stolee@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).