Message ID | pull.1101.v3.git.1640727143.gitgitgadget@gmail.com (mailing list archive) |
---|---|
Headers | show |
Series | Sparse checkout: fix bug with worktree of bare repo | expand |
On Tue, Dec 28, 2021 at 1:32 PM Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com> wrote: > > This series is based on a merge of en/sparse-checkout-set, > en/worktree-chatty-to-stderr, and ds/sparse-checkout-malformed-pattern-fix. I think you mean es/worktree-chatty-to-stderr (not 'en/') > This patch series includes a fix to the bug reported by Sean Allred [1] and > diagnosed by Eric Sunshine [2]. > > The root cause is that 'git sparse-checkout init' writes to the worktree > config without checking that core.bare might need to be set. This only > matters when the base repository is bare, since creating the config.worktree > file and enabling extensions.worktreeConfig will cause Git to treat the base > repo's core.bare=false as important for this worktree. > > This series fixes this, but also puts in place some helpers to prevent this > from happening in the future. While here, some of the config paths are > modified to take a repository struct. > > * 'git sparse-checkout' will now modify the worktree config, if enabled. It > will no longer auto-upgrade users into using worktree config. This sounds dangerous to me. > * The new 'git worktree init-worktree-config' will upgrade users to using > worktree config. It will relocate core.bare and core.worktree if > necessary. This sounds like giving users an extra step to unbreak themselves, instead of just having the commands do it. (And might risk also breaking things in a different direction? I'll have to read over the patches to see...) > * 'git worktree add' will copy the sparse-checkout patterns from the > current worktree to the new one. If worktree config is enabled, then the > config settings from the current worktree are copied to the new > worktree's config file. This sounds awesome. Wahoo! (core.worktree should be cleared, though, and core.bare should either be cleared or set to false if found in the worktree config.) ... > Range-diff vs v2: > > 1: 889e69dc45d = 1: 749ba67d21e setup: use a repository when upgrading format > 2: 3e01356815a = 2: 61b96937016 config: make some helpers repo-aware > 3: ed8e2a7b19d ! 3: e2a0a458115 worktree: add upgrade_to_worktree_config() ... > @@ Commit message > Helped-by: Eric Sunshine <sunshine@sunshineco.com> > Signed-off-by: Derrick Stolee <dstolee@microsoft.com> > > - ## worktree.c ## > + ## Documentation/git-worktree.txt ## > +@@ Documentation/git-worktree.txt: SYNOPSIS > + -------- > + [verse] > + 'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>] > ++'git worktree init-worktree-config' > + 'git worktree list' [-v | --porcelain] > + 'git worktree lock' [--reason <string>] <worktree> > + 'git worktree move' <worktree> <new-path> > +@@ Documentation/git-worktree.txt: checked out in the new working tree, if it's not checked out anywhere > + else, otherwise the command will refuse to create the working tree (unless > + `--force` is used). > + > ++init-worktree-config:: > ++ > ++Initialize config settings to enable worktree-specific config settings. > ++This will set `core.repositoryFormatversion=1` and enable > ++`extensions.worktreeConfig`, which might cause some third-party tools from s/cause/prevent/ ? > ++being able to operate on your repository. See CONFIGURATION FILE for more > ++details. So, if users attempt to use `git worktree add` or `git sparse-checkout {init,set}` without first running this, they can break other worktrees. And if they do run this new command, they potentially break third-party tools or older git versions. Yet, with the very common case (in fact, I'd go so far as to say the nearly universal case) of having both core.bare=false and no core.worktree set, we never had any such problems with the former logic. This seems like a serious regression to me. I'll keep reading. ... > +@@ Documentation/git-worktree.txt: versions will refuse to access repositories with this extension. > + > + Note that in this file, the exception for `core.bare` and `core.worktree` > + is gone. If they exist in `$GIT_DIR/config`, you must move > +-them to the `config.worktree` of the main working tree. You may also > +-take this opportunity to review and move other configuration that you > +-do not want to share to all working trees: > ++them to the `config.worktree` of the main working tree. These keys are > ++moved automatically when you use the `git worktree init-worktree-config` > ++command. > ++ > ++You may also take this opportunity to review and move other configuration > ++that you do not want to share to all working trees: > + > + - `core.worktree` and `core.bare` should never be shared I'm fine with the wording, but technically core.bare=false is fine to share, it's just core.bare=true that is not. (And yes, I agree that core.worktree is never safe to share) ... > 5: 06457fafa78 ! 5: b200819c1bb sparse-checkout: use repo_config_set_worktree_gently() > @@ Commit message > sparse-checkout: use repo_config_set_worktree_gently() > ... > + Let the sparse-checkout builtin use this helper instead of attempting to > + initialize the worktree config on its own. This changes behavior of 'git > + sparse-checkout set' in a few important ways: > > - The fix is to have this assignment into config.worktree be handled by > - the repo_config_set_worktree_gently() helper. > + 1. Git will no longer upgrade the repository format and add the > + worktree config extension. The user should run 'git worktree > + init-worktree-config' to enable this feature. > + > + 2. If worktree config is disabled, then this command will set the > + core.sparseCheckout (and possibly core.sparseCheckoutCone and > + index.sparse) values in the common config file. Yikes. > + 3. If the main worktree is bare, then this command will not put the > + worktree in a broken state. > + > + The main reason to use worktree-specific config for the sparse-checkout > + builtin was to avoid enabling sparse-checkout patterns in one and > + causing a loss of files in another. If a worktree does not have a > + sparse-checkout patterns file, then the sparse-checkout logic will not > + kick in on that worktree. > + > + This new logic introduces a new user pattern that could lead to some > + confusion. Suppose a user has not upgraded to worktree config and > + follows these steps in order: > + > + 1. Enable sparse-checkout in a worktree. > + > + 2. Disable sparse-checkout in that worktree without deleting that > + worktree's sparse-checkout file. > + > + 3. Enable sparse-checkout in another worktree. > + > + After these steps, the first worktree will have sparse-checkout enabled > + with whatever patterns exist. The worktree does not immediately have > + those patterns applied, but a variety of Git commands would apply the > + sparse-checkout patterns and update the worktree state to reflect those > + patterns. This situation is likely very rare and the workaround is to No, it's not even rare, let alone very rare. I'd actually call it common. Since 'sparse-checkout disable' does not delete the sparse-checkout file, and we've encouraged folks to use the sparse-checkout command (or a wrapper thereof) instead of direct editing of the sparse-checkout file (and indeed, the sparse-checkout command will overwrite the sparse-checkout file which further discourages users from feeling they own it), having the file left around after disabling is the common case. So, the only question is, how often do users disable and re-enable sparse-checkout, and potentially only do so in some of their worktrees? At my $DAYJOB, that's actually quite common. I got multiple reports quite soon after introducing our `sparsify` tool about users doing something like this; this is what led me to learn of the extensions.worktreeConfig, and why I pointed it out to you on your first submission of git-sparse-checkout[1] (https://lore.kernel.org/git/CABPp-BFcH5hQqujjmc88L3qGx3QAYZ_chH6PXQXyp13ipfV6hQ@mail.gmail.com/) Some more details about sparse-checkouts at $DAYJOB: * We have numerous users who used to have their own small little repos, and want to still have that experience. sparse-checkouts were a way to provide a small-repo feel for them, and in particular to speed up IDEs that otherwise insist on indexing everything no matter how much we try to tell them to only pay attention to part of the files (and similar speed issues with the build system since gradle configuration is so slow). They want every worktree to be sparse and never face the full repo. I talk about these users the most, because we've mostly satisfied the other users. * We have numerous users who work mostly on specific modules, but occasionally do cross-cutting work. They will have most worktrees be sparse, but keep at least one that is full. They may also undo sparsity briefly and redo it in various worktrees. * We also have a few users who work primarily on cross-cutting features and just keep the full checkout and ignore the sparse-checkout stuff. * There is also a special tool, write-locks.sh or some name like that, which must unsparsify, run something like `./gradle --write-locks` and other stuff, and then re-sparsify. The tool does not work without the full worktree. Now, not all users need to run this, and in fact most users who do probably are the same ones that "occasionally do cross-cutting work", but it's a little bit wider group than that. So we have additional unsparsify/resparsify steps, and it's further complicated by the fact that users may not even know that we do the unsparsification and resparsification behind the scenes for them (our `sparsify` wrapper has a stash-like feature, though I think only allowing for one on the stash, which is called behind the scenes.) The write-locks logic is super slow, which kind of hides the otherwise slow unsparsify/resparsify steps. (For each of the above type of users, we have many folks who don't use worktrees, but they're not relevant to this discussion.) We also have third party git tools, whether jgit (usually via gradle plugins), whatever IDEs tend to use (eclipse used egit, not sure what intellij or visual studio use), probably various special one-off scripts that read a bit more git configuration than they should and do various tasks, and a wide range of git versions in use (though any given user will likely only use one git version, and we are perfectly happy to specify a minimum version for sparse-checkout usage). So that's the range of users for this discussion, but I think we also need to flesh out the caveats of your change since you missed a few: * Even if users haven't sparsified/unsparsified/re-sparsified in another worktree (i.e. they have a worktree that has always been full), the sparse-checkout init/set in another worktree _still_ causes problems because when users switch to the 'full' worktree, contrib/completion/git-prompt.sh will report it as sparse. Users are going to get confused and report bugs just based on their prompt even if it's technically a "dense" worktree. * The cone-mode and sparse-index are also shared between worktrees, which may not present many problems for me right now at $DAYJOB, but could be problematic for other users out there. So, here's the experience I expect from these patches at $DAYJOB: (1) Several users per week hit the case of one worktree being sparsified when it wasn't supposed to be. (2) These users have no idea how to figure out what they need to do to fix it. The init-worktree-config is no more discoverable than the documentation on the official steps for enabling extensions.worktreeConfig (See https://lore.kernel.org/git/CABPp-BGKyDJV9DP+igmCC_Ad0jgvb4aOAYpXWCbx9hW8ShhDQg@mail.gmail.com/ up through the paragraph, "Further, it's not even clear people would look at git-worktree.txt.) (3) Even if they do discover it, and run it, it's an extra step they never needed to take before. Why are we adding a "unbreak these other commands we want to run" step? (4) Also, even if they do discover it, and run it, suddenly we are setting core.repositoryFormatVersion=1. That scares me. I have years of experience at $DAYJOB saying that the tooling we have works fine with extensions.worktreeConfig=true. I have none with setting core.repositoryFormatVersion=1, but now we're effectively requiring it by your documentation. I have no idea how jgit/egit/other-random-stuff interacts with that. I'd be willing to do some tests with targetted users to try to learn more, but suddenly turning it on for everyone in cases that we know worked fine without it previously feels unsafe to me. Maybe I'm over-worrying here, but see also commit 11664196ac ("Revert "check_repository_format_gently(): refuse extensions for old repositories"", 2020-07-15) -- it just feels a bit late to recommend for users, especially when they'll see it as "oh, if you don't want this other bug we recently introduced you need to run this....". So, I'd like to reiterate my earlier suggestion which would avoid these regressions while also fixing the reported bug: * If core.bare=true or core.worktree is set, then at `git worktree add` time, automatically run the logic you have here for init-worktree-config. Having either of those config settings with multiple worktrees is currently broken in all git versions and likely in most all external tools. As such, being aggressive in the new config settings to allow new versions of git to work seems totally safe to me -- we can't be any more broken than we already were. * If core.bare=false and core.worktree is not set, then: * `git sparse-checkout {init,set}` should set extensions.worktreeConfig if not already set, and always set the core.sparse* and index.sparse settings in worktree-specific files. * `git worktree add`, if extensions.worktreeConfig is already set, will copy both the info/sparse-checkout file and the config.worktree settings (module core.bare and core.worktree, if present) to the new worktree
On 12/29/2021 4:39 AM, Elijah Newren wrote: > On Tue, Dec 28, 2021 at 1:32 PM Derrick Stolee via GitGitGadget > <gitgitgadget@gmail.com> wrote: >> >> This series is based on a merge of en/sparse-checkout-set, >> en/worktree-chatty-to-stderr, and ds/sparse-checkout-malformed-pattern-fix. > > I think you mean es/worktree-chatty-to-stderr (not 'en/') Yes. Thanks. >> This patch series includes a fix to the bug reported by Sean Allred [1] and >> diagnosed by Eric Sunshine [2]. >> >> The root cause is that 'git sparse-checkout init' writes to the worktree >> config without checking that core.bare might need to be set. This only >> matters when the base repository is bare, since creating the config.worktree >> file and enabling extensions.worktreeConfig will cause Git to treat the base >> repo's core.bare=false as important for this worktree. >> >> This series fixes this, but also puts in place some helpers to prevent this >> from happening in the future. While here, some of the config paths are >> modified to take a repository struct. >> >> * 'git sparse-checkout' will now modify the worktree config, if enabled. It >> will no longer auto-upgrade users into using worktree config. > > This sounds dangerous to me. > ... >> + Let the sparse-checkout builtin use this helper instead of attempting to >> + initialize the worktree config on its own. This changes behavior of 'git >> + sparse-checkout set' in a few important ways: >> >> - The fix is to have this assignment into config.worktree be handled by >> - the repo_config_set_worktree_gently() helper. >> + 1. Git will no longer upgrade the repository format and add the >> + worktree config extension. The user should run 'git worktree >> + init-worktree-config' to enable this feature. >> + >> + 2. If worktree config is disabled, then this command will set the >> + core.sparseCheckout (and possibly core.sparseCheckoutCone and >> + index.sparse) values in the common config file. > > Yikes. > >> + 3. If the main worktree is bare, then this command will not put the >> + worktree in a broken state. >> + >> + The main reason to use worktree-specific config for the sparse-checkout >> + builtin was to avoid enabling sparse-checkout patterns in one and >> + causing a loss of files in another. If a worktree does not have a >> + sparse-checkout patterns file, then the sparse-checkout logic will not >> + kick in on that worktree. >> + >> + This new logic introduces a new user pattern that could lead to some >> + confusion. Suppose a user has not upgraded to worktree config and >> + follows these steps in order: >> + >> + 1. Enable sparse-checkout in a worktree. >> + >> + 2. Disable sparse-checkout in that worktree without deleting that >> + worktree's sparse-checkout file. >> + >> + 3. Enable sparse-checkout in another worktree. >> + >> + After these steps, the first worktree will have sparse-checkout enabled >> + with whatever patterns exist. The worktree does not immediately have >> + those patterns applied, but a variety of Git commands would apply the >> + sparse-checkout patterns and update the worktree state to reflect those >> + patterns. This situation is likely very rare and the workaround is to > > No, it's not even rare, let alone very rare. I'd actually call it > common. Since 'sparse-checkout disable' does not delete the > sparse-checkout file, and we've encouraged folks to use the > sparse-checkout command (or a wrapper thereof) instead of direct > editing of the sparse-checkout file (and indeed, the sparse-checkout > command will overwrite the sparse-checkout file which further > discourages users from feeling they own it), having the file left > around after disabling is the common case. So, the only question is, > how often do users disable and re-enable sparse-checkout, and > potentially only do so in some of their worktrees? At my $DAYJOB, > that's actually quite common. I got multiple reports quite soon after > introducing our `sparsify` tool about users doing something like this; > this is what led me to learn of the extensions.worktreeConfig, and why > I pointed it out to you on your first submission of > git-sparse-checkout[1] > (https://lore.kernel.org/git/CABPp-BFcH5hQqujjmc88L3qGx3QAYZ_chH6PXQXyp13ipfV6hQ@mail.gmail.com/) Thank you for these comments and the detailed descriptions of things from your $DAYJOB. That's helpful context and I'm happy to switch back to enabling the extension in the sparse-checkout builtin. I might need to rearrange the code so there is an API in worktree.c instead of just the subcommand in builtin/worktree.c, but that's pretty minor. I'll keep Eric's earlier suggestion to have the upgrade be a separate call from the repo_config_set_worktree_gently(). Thanks, -Stolee
On Wed, Dec 29, 2021 at 4:40 AM Elijah Newren <newren@gmail.com> wrote:> > On Tue, Dec 28, 2021 at 1:32 PM Derrick Stolee via GitGitGadget > <gitgitgadget@gmail.com> wrote: > > ++init-worktree-config:: > > ++ > > ++Initialize config settings to enable worktree-specific config settings. > > ++This will set `core.repositoryFormatversion=1` and enable > > ++`extensions.worktreeConfig`, which might cause some third-party tools from > > ++being able to operate on your repository. See CONFIGURATION FILE for more > > ++details. > > So, if users attempt to use `git worktree add` or `git sparse-checkout > {init,set}` without first running this, they can break other > worktrees. And if they do run this new command, they potentially > break third-party tools or older git versions. When you say "can break other worktrees", you don't necessarily mean that in general but rather in regard to sparse-checkout -- in particular, the sparse-checkout config settings and the `info/sparse-checkout file` -- correct? (Genuine question; I want to make sure that I'm actually understanding the issues under discussion.) > > + After these steps, the first worktree will have sparse-checkout enabled > > + with whatever patterns exist. The worktree does not immediately have > > + those patterns applied, but a variety of Git commands would apply the > > + sparse-checkout patterns and update the worktree state to reflect those > > + patterns. This situation is likely very rare and the workaround is to > > No, it's not even rare, let alone very rare. I'd actually call it > common. Since 'sparse-checkout disable' does not delete the > sparse-checkout file, and we've encouraged folks to use the > sparse-checkout command (or a wrapper thereof) instead of direct > editing of the sparse-checkout file (and indeed, the sparse-checkout > command will overwrite the sparse-checkout file which further > discourages users from feeling they own it), having the file left > around after disabling is the common case. So, the only question is, > how often do users disable and re-enable sparse-checkout, and > potentially only do so in some of their worktrees? At my $DAYJOB, > that's actually quite common. I got multiple reports quite soon after > introducing our `sparsify` tool about users doing something like this; > this is what led me to learn of the extensions.worktreeConfig, and why > I pointed it out to you on your first submission of > git-sparse-checkout[1] > (https://lore.kernel.org/git/CABPp-BFcH5hQqujjmc88L3qGx3QAYZ_chH6PXQXyp13ipfV6hQ@mail.gmail.com/) I think the link you provide here answers the genuine question I had asked in [1] where I didn't understand why git-sparse-checkout is forcing the repository to use per-worktree configuration. I also just (re)discovered [2] which makes it clear that per-worktree sparse-checkout was considered important very early on in the development of "multiple checkouts". [1]: https://lore.kernel.org/git/CAPig+cRombN-8g0t7Hs9qQypJoY41gK3+kvypH4D0G6EB4JgbQ@mail.gmail.com/ [2]: https://lore.kernel.org/git/1404891197-18067-32-git-send-email-pclouds@gmail.com/ > So, here's the experience I expect from these patches at $DAYJOB: > (1) Several users per week hit the case of one worktree being > sparsified when it wasn't supposed to be. > (2) These users have no idea how to figure out what they need to do > to fix it. The init-worktree-config is no more discoverable than the > documentation on the official steps for enabling > extensions.worktreeConfig (See > https://lore.kernel.org/git/CABPp-BGKyDJV9DP+igmCC_Ad0jgvb4aOAYpXWCbx9hW8ShhDQg@mail.gmail.com/ > up through the paragraph, "Further, it's not even clear people would > look at git-worktree.txt.) > (3) Even if they do discover it, and run it, it's an extra step they > never needed to take before. Why are we adding a "unbreak these other > commands we want to run" step? > (4) Also, even if they do discover it, and run it, suddenly we are > setting core.repositoryFormatVersion=1. That scares me. I have years > of experience at $DAYJOB saying that the tooling we have works fine > with extensions.worktreeConfig=true. I have none with setting > core.repositoryFormatVersion=1, but now we're effectively requiring it > by your documentation. I have no idea how > jgit/egit/other-random-stuff interacts with that. I'd be willing to > do some tests with targetted users to try to learn more, but suddenly > turning it on for everyone in cases that we know worked fine without > it previously feels unsafe to me. Maybe I'm over-worrying here, but > see also commit 11664196ac ("Revert "check_repository_format_gently(): > refuse > extensions for old repositories"", 2020-07-15) -- it just feels a bit > late to recommend for users, especially when they'll see it as "oh, if > you don't want this other bug we recently introduced you need to run > this....". Point #4 is pretty compelling, and the "ship" of enforcing `core.repositoryFormatVersion=1` when using `extension` configs has "already sailed" anyhow, as 11664196ac ("Revert "check_repository_format_gently(): refuse extensions for old repositories"", 2020-07-15) clearly indicates. > So, I'd like to reiterate my earlier suggestion which would avoid > these regressions while also fixing the reported bug: > * If core.bare=true or core.worktree is set, then at `git worktree > add` time, automatically run the logic you have here for > init-worktree-config. Having either of those config settings with > multiple worktrees is currently broken in all git versions and likely > in most all external tools. As such, being aggressive in the new > config settings to allow new versions of git to work seems totally > safe to me -- we can't be any more broken than we already were. > * If core.bare=false and core.worktree is not set, then: > * `git sparse-checkout {init,set}` should set > extensions.worktreeConfig if not already set, and always set the > core.sparse* and index.sparse settings in worktree-specific files. > * `git worktree add`, if extensions.worktreeConfig is already set, > will copy both the info/sparse-checkout file and the config.worktree > settings (module core.bare and core.worktree, if present) to the new > worktree Thanks for the clearly written enumeration of how you expect this to work. This summary pretty well (or entirely) captures the conclusions I arrived at, as well, after devoting a chunk of time today thinking through the cases. If I'm understanding everything correctly, the approach outlined here solves the bare-worktree problem in the least invasive and least dangerous way (for older Git versions and foreign tools). And we don't even need the `git worktree init-worktree-config` subcommand (though we need the underlying functionality).
On Wed, Dec 29, 2021 at 12:39 PM Derrick Stolee <stolee@gmail.com> wrote: > On 12/29/2021 4:39 AM, Elijah Newren wrote: > > No, it's not even rare, let alone very rare. I'd actually call it > > common. Since 'sparse-checkout disable' does not delete the > > sparse-checkout file, and we've encouraged folks to use the > > sparse-checkout command (or a wrapper thereof) instead of direct > > editing of the sparse-checkout file (and indeed, the sparse-checkout > > command will overwrite the sparse-checkout file which further > > discourages users from feeling they own it), having the file left > > around after disabling is the common case. So, the only question is, > > how often do users disable and re-enable sparse-checkout, and > > potentially only do so in some of their worktrees? At my $DAYJOB, > > that's actually quite common. I got multiple reports quite soon after > > introducing our `sparsify` tool about users doing something like this; > > this is what led me to learn of the extensions.worktreeConfig, and why > > I pointed it out to you on your first submission of > > git-sparse-checkout[1] > > (https://lore.kernel.org/git/CABPp-BFcH5hQqujjmc88L3qGx3QAYZ_chH6PXQXyp13ipfV6hQ@mail.gmail.com/) > > Thank you for these comments and the detailed descriptions of things > from your $DAYJOB. That's helpful context and I'm happy to switch back > to enabling the extension in the sparse-checkout builtin. I might need > to rearrange the code so there is an API in worktree.c instead of just > the subcommand in builtin/worktree.c, but that's pretty minor. I'll > keep Eric's earlier suggestion to have the upgrade be a separate call > from the repo_config_set_worktree_gently(). Thanks.
On 12/30/2021 2:40 AM, Eric Sunshine wrote: > On Wed, Dec 29, 2021 at 4:40 AM Elijah Newren <newren@gmail.com> wrote:> Taking time to focus only on this outline here: >> So, I'd like to reiterate my earlier suggestion which would avoid >> these regressions while also fixing the reported bug: >> * If core.bare=true or core.worktree is set, then at `git worktree >> add` time, automatically run the logic you have here for >> init-worktree-config. Having either of those config settings with >> multiple worktrees is currently broken in all git versions and likely >> in most all external tools. As such, being aggressive in the new >> config settings to allow new versions of git to work seems totally >> safe to me -- we can't be any more broken than we already were. I'm not sure I agree with the "currently broken in all git versions" because when extensions.worktreeConfig is not enabled, the core.bare and core.worktree settings are ignored by the worktrees. This upgrade during 'add' is the only thing I am not so sure about. >> * If core.bare=false and core.worktree is not set, then: >> * `git sparse-checkout {init,set}` should set >> extensions.worktreeConfig if not already set, and always set the >> core.sparse* and index.sparse settings in worktree-specific files. This should happen no matter the case of core.bare and core.worktree existing, right? >> * `git worktree add`, if extensions.worktreeConfig is already set, >> will copy both the info/sparse-checkout file and the config.worktree >> settings (module core.bare and core.worktree, if present) to the new >> worktree and here, 'git worktree add' should always copy the info/sparse-checkout file (if core.sparseCheckout is enabled) and copy the config.worktree settings if extensions.worktreeConfig is enabled (and filter out core.bare and core.worktree in the process). > Thanks for the clearly written enumeration of how you expect this to > work. This summary pretty well (or entirely) captures the conclusions > I arrived at, as well, after devoting a chunk of time today thinking > through the cases. If I'm understanding everything correctly, the > approach outlined here solves the bare-worktree problem in the least > invasive and least dangerous way (for older Git versions and foreign > tools). And we don't even need the `git worktree init-worktree-config` > subcommand (though we need the underlying functionality). I'm happy to drop the subcommand in favor of some documentation in git-config.txt (Documentation/config/extensions.txt to be exact). Thanks, -Stolee
On Wed, Dec 29, 2021 at 11:40 PM Eric Sunshine <sunshine@sunshineco.com> wrote: > > On Wed, Dec 29, 2021 at 4:40 AM Elijah Newren <newren@gmail.com> wrote:> > > On Tue, Dec 28, 2021 at 1:32 PM Derrick Stolee via GitGitGadget > > <gitgitgadget@gmail.com> wrote: > > > ++init-worktree-config:: > > > ++ > > > ++Initialize config settings to enable worktree-specific config settings. > > > ++This will set `core.repositoryFormatversion=1` and enable > > > ++`extensions.worktreeConfig`, which might cause some third-party tools from > > > ++being able to operate on your repository. See CONFIGURATION FILE for more > > > ++details. > > > > So, if users attempt to use `git worktree add` or `git sparse-checkout > > {init,set}` without first running this, they can break other > > worktrees. And if they do run this new command, they potentially > > break third-party tools or older git versions. > > When you say "can break other worktrees", you don't necessarily mean > that in general but rather in regard to sparse-checkout -- in > particular, the sparse-checkout config settings and the > `info/sparse-checkout file` -- correct? (Genuine question; I want to > make sure that I'm actually understanding the issues under > discussion.) Yes, thanks for the clarifications. ... > > So, I'd like to reiterate my earlier suggestion which would avoid > > these regressions while also fixing the reported bug: > > * If core.bare=true or core.worktree is set, then at `git worktree > > add` time, automatically run the logic you have here for > > init-worktree-config. Having either of those config settings with > > multiple worktrees is currently broken in all git versions and likely > > in most all external tools. As such, being aggressive in the new > > config settings to allow new versions of git to work seems totally > > safe to me -- we can't be any more broken than we already were. > > * If core.bare=false and core.worktree is not set, then: > > * `git sparse-checkout {init,set}` should set > > extensions.worktreeConfig if not already set, and always set the > > core.sparse* and index.sparse settings in worktree-specific files. > > * `git worktree add`, if extensions.worktreeConfig is already set, > > will copy both the info/sparse-checkout file and the config.worktree > > settings (module core.bare and core.worktree, if present) to the new > > worktree > > Thanks for the clearly written enumeration of how you expect this to > work. This summary pretty well (or entirely) captures the conclusions > I arrived at, as well, after devoting a chunk of time today thinking > through the cases. If I'm understanding everything correctly, the > approach outlined here solves the bare-worktree problem in the least > invasive and least dangerous way (for older Git versions and foreign > tools). And we don't even need the `git worktree init-worktree-config` > subcommand (though we need the underlying functionality). I'm glad it helps, and that we appear to be moving towards consensus. :-)
On Thu, Dec 30, 2021 at 9:41 AM Derrick Stolee <stolee@gmail.com> wrote: > > On 12/30/2021 2:40 AM, Eric Sunshine wrote: > > On Wed, Dec 29, 2021 at 4:40 AM Elijah Newren <newren@gmail.com> wrote:> > > Taking time to focus only on this outline here: > > >> So, I'd like to reiterate my earlier suggestion which would avoid > >> these regressions while also fixing the reported bug: > > >> * If core.bare=true or core.worktree is set, then at `git worktree > >> add` time, automatically run the logic you have here for > >> init-worktree-config. Having either of those config settings with > >> multiple worktrees is currently broken in all git versions and likely > >> in most all external tools. As such, being aggressive in the new > >> config settings to allow new versions of git to work seems totally > >> safe to me -- we can't be any more broken than we already were. > > I'm not sure I agree with the "currently broken in all git versions" > because when extensions.worktreeConfig is not enabled, the core.bare > and core.worktree settings are ignored by the worktrees. This upgrade > during 'add' is the only thing I am not so sure about. Oh, you're right; I mis-spoke. If someone has core.bare=true and has multiple worktrees, AND never attempts to use sparse-checkouts OR otherwise set extensions.worktreeConfig, then git still works due to git's special-case logic that will override core.bare in this configuration. It's just setting them up for a ticking time bomb, waiting for them to either use an external tool that doesn't share that special case override-core.bare logic, or for the user to decide to set extensions.worktreeConfig directly or use sparse-checkouts. > >> * If core.bare=false and core.worktree is not set, then: > > >> * `git sparse-checkout {init,set}` should set > >> extensions.worktreeConfig if not already set, and always set the > >> core.sparse* and index.sparse settings in worktree-specific files. > > This should happen no matter the case of core.bare and core.worktree > existing, right? Hmm. I think that's safe for people who cloned and used `git worktree add` with newer git versions, since `git worktree add` will have moved core.bare and core.worktree to the config.worktree file when those have non-default values. But, we might want to help out the folks who have existing repos with which they have used older git versions. So, we could have `git sparse-checkout {init,set}` check for non-default values of core.bare/core.worktree in the shared config file, and, if found, exit with an error which point users at some relevant documentation (which may just suggest 'git worktree add temporary && git worktree remove temporary' as a workaround for those caught in such a state.) > >> * `git worktree add`, if extensions.worktreeConfig is already set, > >> will copy both the info/sparse-checkout file and the config.worktree > >> settings (module core.bare and core.worktree, if present) to the new > >> worktree > > and here, 'git worktree add' should always copy the info/sparse-checkout > file (if core.sparseCheckout is enabled) and copy the config.worktree > settings if extensions.worktreeConfig is enabled (and filter out > core.bare and core.worktree in the process). Right. > > Thanks for the clearly written enumeration of how you expect this to > > work. This summary pretty well (or entirely) captures the conclusions > > I arrived at, as well, after devoting a chunk of time today thinking > > through the cases. If I'm understanding everything correctly, the > > approach outlined here solves the bare-worktree problem in the least > > invasive and least dangerous way (for older Git versions and foreign > > tools). And we don't even need the `git worktree init-worktree-config` > > subcommand (though we need the underlying functionality). > > I'm happy to drop the subcommand in favor of some documentation in > git-config.txt (Documentation/config/extensions.txt to be exact). You may also want to make the two existing references to extensions.worktreeConfig within Documentation/git-config.txt point users at the extended documentation you add to Documentation/config/extensions.txt. (Remember, I found a reference to extensions.worktreeConfig, tried it, and started using and recommending it without it ever occurring to me that there was a more detailed explanation elsewhere, so only adding to Documentation/config/extensions.txt might run into the same discoverability issues.)
On Thu, Dec 30, 2021 at 2:29 PM Elijah Newren <newren@gmail.com> wrote: > On Thu, Dec 30, 2021 at 9:41 AM Derrick Stolee <stolee@gmail.com> wrote: > > On 12/30/2021 2:40 AM, Eric Sunshine wrote: > > > On Wed, Dec 29, 2021 at 4:40 AM Elijah Newren <newren@gmail.com> wrote:> > > >> * If core.bare=true or core.worktree is set, then at `git worktree > > >> add` time, automatically run the logic you have here for > > >> init-worktree-config. Having either of those config settings with > > >> multiple worktrees is currently broken in all git versions and likely > > >> in most all external tools. As such, being aggressive in the new > > >> config settings to allow new versions of git to work seems totally > > >> safe to me -- we can't be any more broken than we already were. > > > > I'm not sure I agree with the "currently broken in all git versions" > > because when extensions.worktreeConfig is not enabled, the core.bare > > and core.worktree settings are ignored by the worktrees. This upgrade > > during 'add' is the only thing I am not so sure about. > > Oh, you're right; I mis-spoke. If someone has core.bare=true and has > multiple worktrees, AND never attempts to use sparse-checkouts OR > otherwise set extensions.worktreeConfig, then git still works due to > git's special-case logic that will override core.bare in this > configuration. It's just setting them up for a ticking time bomb, > waiting for them to either use an external tool that doesn't share > that special case override-core.bare logic, or for the user to decide > to set extensions.worktreeConfig directly or use sparse-checkouts. So, how does this alter the proposed logic? Or does it? Does the above condition get revised to: if extensions.worktreeConfig=true and (.git/config contains core.bare=true or core.worktree): relocate core.bare/core.worktree to .git/config.worktree That is, we need to relocate core.bare and core.worktree from .git/config to .git/config.worktree if and only if extensions.worktreeConfig=true (because, due to the special-case handling, those two keys don't interfere with anything when extensions.worktreeConfig is not true). This, of course, doesn't help the case if someone has existing worktrees and decides to flip extensions.worktreeConfig to true without doing the manual bookkeeping, but that case has always been broken (and is documented, though not necessarily where people will look). The new `git worktree add` logic, however, will fix that brokenness automatically when a new worktree is added. > > >> * If core.bare=false and core.worktree is not set, then: > > > > >> * `git sparse-checkout {init,set}` should set > > >> extensions.worktreeConfig if not already set, and always set the > > >> core.sparse* and index.sparse settings in worktree-specific files. > > > > This should happen no matter the case of core.bare and core.worktree > > existing, right? > > Hmm. I think that's safe for people who cloned and used `git worktree > add` with newer git versions, since `git worktree add` will have moved > core.bare and core.worktree to the config.worktree file when those > have non-default values. > > But, we might want to help out the folks who have existing repos with > which they have used older git versions. So, we could have `git > sparse-checkout {init,set}` check for non-default values of > core.bare/core.worktree in the shared config file, and, if found, exit > with an error which point users at some relevant documentation (which > may just suggest 'git worktree add temporary && git worktree remove > temporary' as a workaround for those caught in such a state.) I'm probably missing something obvious, but rather than error out, can't we just automatically relocate core.bare and core.worktree from .git/config to .git/config.worktree in this case?