git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2 3/5] worktree: add upgrade_to_worktree_config()

From
Derrick Stolee <stolee@gmail.com>
Date
Dec 28, 2021, 15:03 UTC
Message-ID
<53f3531d-29ee-f16e-1d60-21ca7b4a3fbd@gmail.com>
In-Reply-To
<CAPig+cQrJ9yWjkc8VMu=uyx_qtrXdL3cNnxLVafoxOo6e-r9kw@mail.gmail.com>
On 12/21/2021 7:45 PM, Eric Sunshine wrote:
Show 19 quoted lines
> 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."

Bare worktrees don't exist, that is correct. But if one existed it would be a directory where you could operate as if it is a bare repo, but it has its own HEAD different from the base repo's HEAD. Not sure why one would want it.

I guess the question is: what happens if someone writes core.bare=true
into their worktree config? A question to resolve another day, perhaps.
 
Show 14 quoted lines
>> 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:
Good suggestions to add the necessary context here. Thanks.
Show 44 quoted lines
>     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.

That would be good. I originally erred on the side of least complicated but slower because this is not run very often.

Show 14 quoted lines
>> +       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.

'repo_config' is too generic, because I want the worktree config for the "original" repo. I chose to call that the "base" repo and its worktree config. Shared_config is a good name, though.

Show 12 quoted lines
>> +       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".

Yes, but specific to the original/root/bare repo. I'm open to preferences here, but "repo" isn't specific enough.

Show 40 quoted lines
>> +       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).

It took me a long time to actually understand the purpose of core.worktree, since it seems in conflict with the 'git worktree' feature. Indeed, it is special-cased the same way core.bare is, so this relocation is required.

Show 23 quoted lines
>> +       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`

This order can still cause some issues, specifically the worktree will still think it is bare or the core.worktree value is incorrect, but that is less serious than a broken base repo.

Show 7 quoted lines
>> +cleanup:
>> +       git_configset_clear(&cs);
>> +       free(base_config_file);
>> +       free(base_worktree_file);
>> +       trace2_printf("returning %d", res);
> 
> Is this leftover debugging or intentional?
Leftover debugging. Thanks for catching.

Thanks, -Stolee

Previous: Eric SunshineNext: Eric Sunshine
Message 21 of 138 in “Sparse checkout: fix bug with worktree of bare repo”
  1. 0/4 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Dec 20, 2021
  2. 1/4 setup: use a repository when upgrading formatDerrick Stolee via GitGitGadget, Dec 20, 2021
  3. 2/4 config: make some helpers repo-awareDerrick Stolee via GitGitGadget, Dec 20, 2021
  4. 3/4 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 20, 2021
  5. Derrick StoleeDec 20, 2021
  6. Eric SunshineDec 21, 2021
  7. Eric SunshineDec 21, 2021
  8. Derrick StoleeDec 21, 2021
  9. Eric SunshineDec 21, 2021
  10. Derrick StoleeDec 21, 2021
  11. Eric SunshineDec 21, 2021
  12. 4/4 sparse-checkout: use repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 20, 2021
  13. Eric SunshineDec 20, 2021
  14. Derrick StoleeDec 20, 2021
  15. Eric SunshineDec 21, 2021
  16. 0/5 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Dec 21, 2021
  17. 1/5 setup: use a repository when upgrading formatDerrick Stolee via GitGitGadget, Dec 21, 2021
  18. 2/5 config: make some helpers repo-awareDerrick Stolee via GitGitGadget, Dec 21, 2021
  19. 3/5 worktree: add upgrade_to_worktree_config()Derrick Stolee via GitGitGadget, Dec 21, 2021
  20. Eric SunshineDec 22, 2021
  21. Derrick StoleeDec 28, 2021
  22. Eric SunshineDec 28, 2021
  23. Derrick StoleeDec 28, 2021
  24. Junio C HamanoDec 22, 2021
  25. Derrick StoleeDec 28, 2021
  26. 4/5 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 21, 2021
  27. Eric SunshineDec 22, 2021
  28. 5/5 sparse-checkout: use repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 21, 2021
  29. Eric SunshineDec 22, 2021
  30. Eric SunshineDec 22, 2021
  31. Elijah NewrenDec 22, 2021
  32. Eric SunshineDec 27, 2021
  33. Eric SunshineDec 27, 2021
  34. Elijah NewrenDec 27, 2021
  35. Eric SunshineDec 28, 2021
  36. Eric SunshineDec 30, 2021
  37. Elijah NewrenDec 30, 2021
  38. Elijah NewrenDec 27, 2021
  39. Eric SunshineDec 28, 2021
  40. Elijah NewrenDec 28, 2021
  41. Eric SunshineDec 30, 2021
  42. Elijah NewrenDec 30, 2021
  43. Eric SunshineJan 3, 2022
  44. 0/6 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Dec 28, 2021
  45. 1/6 setup: use a repository when upgrading formatDerrick Stolee via GitGitGadget, Dec 28, 2021
  46. 2/6 config: make some helpers repo-awareDerrick Stolee via GitGitGadget, Dec 28, 2021
  47. 3/6 worktree: add 'init-worktree-config' subcommandDerrick Stolee via GitGitGadget, Dec 28, 2021
  48. Eric SunshineDec 29, 2021
  49. Eric SunshineDec 30, 2021
  50. Derrick StoleeDec 30, 2021
  51. Eric SunshineJan 3, 2022
  52. 4/6 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 28, 2021
  53. 5/6 sparse-checkout: use repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Dec 28, 2021
  54. Eric SunshineDec 30, 2021
  55. 6/6 worktree: copy sparse-checkout patterns and config on addDerrick Stolee via GitGitGadget, Dec 28, 2021
  56. Eric SunshineDec 29, 2021
  57. Derrick StoleeDec 29, 2021
  58. Elijah NewrenDec 29, 2021
  59. Derrick StoleeDec 29, 2021
  60. Elijah NewrenDec 29, 2021
  61. Eric SunshineDec 30, 2021
  62. Eric SunshineDec 30, 2021
  63. Elijah NewrenDec 29, 2021
  64. Derrick StoleeDec 29, 2021
  65. Eric SunshineDec 30, 2021
  66. Eric SunshineDec 30, 2021
  67. Derrick StoleeDec 30, 2021
  68. Elijah NewrenDec 30, 2021
  69. Eric SunshineJan 3, 2022
  70. Elijah NewrenDec 30, 2021
  71. 0/5 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Jan 25, 2022
  72. 2/5 worktree: create init_worktree_config()Derrick Stolee via GitGitGadget, Jan 25, 2022
  73. Elijah NewrenJan 27, 2022
  74. 3/5 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Jan 25, 2022
  75. 1/5 Documentation: add extensions.worktreeConfig detailsDerrick Stolee via GitGitGadget, Jan 25, 2022
  76. Bagas SanjayaJan 26, 2022
  77. Derrick StoleeJan 27, 2022
  78. Elijah NewrenJan 27, 2022
  79. Derrick StoleeJan 27, 2022
  80. 4/5 sparse-checkout: set worktree-config correctlyDerrick Stolee via GitGitGadget, Jan 25, 2022
  81. Elijah NewrenJan 27, 2022
  82. Derrick StoleeJan 27, 2022
  83. 5/5 worktree: copy sparse-checkout patterns and config on addDerrick Stolee via GitGitGadget, Jan 25, 2022
  84. Elijah NewrenJan 27, 2022
  85. Elijah NewrenJan 27, 2022
  86. Derrick StoleeJan 27, 2022
  87. 0/5 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Jan 31, 2022
  88. 1/5 Documentation: add extensions.worktreeConfig detailsDerrick Stolee via GitGitGadget, Jan 31, 2022
  89. Eric SunshineFeb 6, 2022
  90. 2/5 worktree: create init_worktree_config()Derrick Stolee via GitGitGadget, Jan 31, 2022
  91. Eric SunshineFeb 6, 2022
  92. 3/5 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Jan 31, 2022
  93. 4/5 sparse-checkout: set worktree-config correctlyDerrick Stolee via GitGitGadget, Jan 31, 2022
  94. Eric SunshineFeb 6, 2022
  95. 5/5 worktree: copy sparse-checkout patterns and config on addDerrick Stolee via GitGitGadget, Jan 31, 2022
  96. Jean-Noël AVILAFeb 6, 2022
  97. Derrick StoleeFeb 7, 2022
  98. Jean-Noël AvilaFeb 9, 2022
  99. Derrick StoleeFeb 9, 2022
  100. Eric SunshineFeb 6, 2022
  101. Eric SunshineFeb 6, 2022
  102. Derrick StoleeFeb 7, 2022
  103. Eric SunshineFeb 15, 2022
  104. Derrick StoleeFeb 16, 2022
  105. Elijah NewrenJan 31, 2022
  106. 0/6 Sparse checkout: fix bug with worktree of bare repoDerrick Stolee via GitGitGadget, Feb 7, 2022
  107. 1/6 Documentation: add extensions.worktreeConfig detailsDerrick Stolee via GitGitGadget, Feb 7, 2022
  108. Junio C HamanoFeb 8, 2022
  109. Derrick StoleeFeb 9, 2022
  110. Junio C HamanoFeb 9, 2022
  111. Derrick StoleeFeb 9, 2022
  112. Elijah NewrenFeb 9, 2022
  113. Junio C HamanoFeb 9, 2022
  114. Eric SunshineFeb 15, 2022
  115. Junio C HamanoFeb 16, 2022
  116. Elijah NewrenFeb 9, 2022
  117. Junio C HamanoFeb 9, 2022
  118. 2/6 worktree: create init_worktree_config()Derrick Stolee via GitGitGadget, Feb 7, 2022
  119. Junio C HamanoFeb 8, 2022
  120. Derrick StoleeFeb 9, 2022
  121. Junio C HamanoFeb 9, 2022
  122. Elijah NewrenFeb 9, 2022
  123. 3/6 config: add repo_config_set_worktree_gently()Derrick Stolee via GitGitGadget, Feb 7, 2022
  124. Junio C HamanoFeb 8, 2022
  125. Derrick StoleeFeb 9, 2022
  126. Junio C HamanoFeb 9, 2022
  127. Derrick StoleeFeb 10, 2022
  128. Junio C HamanoFeb 10, 2022
  129. 4/6 sparse-checkout: set worktree-config correctlyDerrick Stolee via GitGitGadget, Feb 7, 2022
  130. 5/6 worktree: copy sparse-checkout patterns and config on addDerrick Stolee via GitGitGadget, Feb 7, 2022
  131. Eric SunshineFeb 15, 2022
  132. 6/6 config: make git_configset_get_string_tmp() privateDerrick Stolee via GitGitGadget, Feb 7, 2022
  133. Elijah NewrenFeb 8, 2022
  134. Eric SunshineFeb 8, 2022
  135. Elijah NewrenFeb 8, 2022
  136. Eric SunshineFeb 8, 2022
  137. Eric SunshineFeb 16, 2022
  138. Derrick StoleeFeb 8, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.