git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: stolee@gmail.com, sunshine@sunshineco.com, allred.sean@gmail.com,
	gitster@pobox.com, Elijah Newren <newren@gmail.com>,
	Derrick Stolee <derrickstolee@github.com>,
	Derrick Stolee <dstolee@microsoft.com>
Subject: [PATCH v3 3/6] worktree: add 'init-worktree-config' subcommand
Date: Tue, 28 Dec 2021 21:32:20 +0000	[thread overview]
Message-ID: <e2a0a458115a26cfb855f7040f15e5198072b3a5.1640727143.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1101.v3.git.1640727143.gitgitgadget@gmail.com>

From: Derrick Stolee <dstolee@microsoft.com>

Some features, such as the sparse-checkout builtin, currently use the
worktree config extension. It might seem simple to upgrade the
repository format and add extensions.worktreeConfig, which is what
happens in the sparse-checkout builtin. However, this is overly
simplistic and can cause issues in some cases. We will transition away
from making this upgrade automatically, but first we will make an easy
way for users to upgrade their repositories correctly.

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.

Similarly, the core.worktree config setting is a precursor to the 'git
worktree' feature, allowing config to point to a different worktree,
presumably temporarily. This is special-cased to be ignored in a
worktree, but that case is dropped when worktree config is enabled.

To help resolve this transition, create the 'git worktree
init-worktree-config' helper. This new subcommand does the following:

 1. Set core.repositoryFormatVersion to 1 in the common config file.
 2. Set extensions.worktreeConfig to true in the common config file.
 3. If core.bare is true in the common config file, then move that
    setting to the main worktree's config file.
 4. Move the core.worktree config value to the main worktree's config
    file.

If the repository is already configured to use worktree config, then
none of these steps happen. This preserves any state that the user might
have created on purpose.

Update the documentation to mention this subcommand as the proper way to
upgrade to worktree config files.

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.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
---
 Documentation/git-worktree.txt           | 22 +++++--
 builtin/worktree.c                       | 82 ++++++++++++++++++++++++
 t/t2407-worktree-init-worktree-config.sh | 68 ++++++++++++++++++++
 3 files changed, 167 insertions(+), 5 deletions(-)
 create mode 100755 t/t2407-worktree-init-worktree-config.sh

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 9e862fbcf79..0f0642ac039 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -10,6 +10,7 @@ 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>
@@ -92,6 +93,14 @@ 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
+being able to operate on your repository. See CONFIGURATION FILE for more
+details.
+
 list::
 
 List details of each working tree.  The main working tree is listed first,
@@ -290,10 +299,10 @@ already present in the config file, they will be applied to the main
 working trees only.
 
 In order to have configuration specific to working trees, you can turn
-on the `worktreeConfig` extension, e.g.:
+on the `worktreeConfig` extension, using this command:
 
 ------------
-$ git config extensions.worktreeConfig true
+$ git worktree init-worktree-config
 ------------
 
 In this mode, specific configuration stays in the path pointed by `git
@@ -303,9 +312,12 @@ 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
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index a57fcd0f3c5..937ee6fc38b 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -17,6 +17,7 @@
 
 static const char * const worktree_usage[] = {
 	N_("git worktree add [<options>] <path> [<commit-ish>]"),
+	N_("git worktree init-worktree-config"),
 	N_("git worktree list [<options>]"),
 	N_("git worktree lock [<options>] <path>"),
 	N_("git worktree move <worktree> <new-path>"),
@@ -1031,6 +1032,85 @@ static int repair(int ac, const char **av, const char *prefix)
 	return rc;
 }
 
+static int move_config_setting(const char *key, const char *value,
+			       const char *from_file, const char *to_file)
+{
+	if (git_config_set_in_file_gently(to_file, key, value))
+		return error(_("unable to set %s in '%s'"), key, to_file);
+	if (git_config_set_in_file_gently(from_file, key, NULL))
+		return error(_("unable to unset %s in '%s'"), key, from_file);
+	return 0;
+}
+
+static int init_worktree_config(int ac, const char **av, const char *prefix)
+{
+	struct repository *r = the_repository;
+	struct option options[] = {
+		OPT_END()
+	};
+	int res = 0;
+	int bare = 0;
+	struct config_set cs = { 0 };
+	const char *core_worktree;
+	char *common_config_file = xstrfmt("%s/config", r->commondir);
+	char *main_worktree_file = xstrfmt("%s/config.worktree", r->commondir);
+
+	/* Report error on any arguments */
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac)
+		usage_with_options(worktree_usage, options);
+
+	git_configset_init(&cs);
+	git_configset_add_file(&cs, common_config_file);
+
+	/*
+	 * If the format and extension are already enabled, then we can
+	 * skip the upgrade process.
+	 */
+	if (repository_format_worktree_config)
+		return 0;
+
+	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;
+	}
+
+	/*
+	 * If core.bare is true in the common config file, then we need to
+	 * move it to the base worktree's config file or it will break all
+	 * worktrees. If it is false, then leave it in place because it
+	 * _could_ be negating a global core.bare=true.
+	 */
+	if (!git_configset_get_bool(&cs, "core.bare", &bare) && bare) {
+		if ((res = move_config_setting("core.bare", "true",
+					       common_config_file,
+					       main_worktree_file)))
+			goto cleanup;
+	}
+	/*
+	 * If core.worktree is set, then the base worktree is located
+	 * somewhere different than the parent of the common Git dir.
+	 * Relocate that value to avoid breaking all worktrees with this
+	 * upgrade to worktree config.
+	 */
+	if (!git_configset_get_string_tmp(&cs, "core.worktree", &core_worktree)) {
+		if ((res = move_config_setting("core.worktree", core_worktree,
+					       common_config_file,
+					       main_worktree_file)))
+			goto cleanup;
+	}
+
+cleanup:
+	git_configset_clear(&cs);
+	free(common_config_file);
+	free(main_worktree_file);
+	return res;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -1045,6 +1125,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		prefix = "";
 	if (!strcmp(av[1], "add"))
 		return add(ac - 1, av + 1, prefix);
+	if (!strcmp(av[1], "init-worktree-config"))
+		return init_worktree_config(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "prune"))
 		return prune(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "list"))
diff --git a/t/t2407-worktree-init-worktree-config.sh b/t/t2407-worktree-init-worktree-config.sh
new file mode 100755
index 00000000000..b3bd0fa1322
--- /dev/null
+++ b/t/t2407-worktree-init-worktree-config.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+test_description='test git worktree init-worktree-config'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	git init base &&
+	test_commit -C base commit &&
+	git -C base worktree add --detach worktree
+'
+
+reset_config_when_finished () {
+	test_when_finished git -C base config --unset core.repositoryFormatVersion &&
+	test_when_finished git -C base config --unset extensions.worktreeConfig &&
+	rm -rf base/.git/config.worktree &&
+	rm -rf base/.git/worktrees/worktree/config.worktree
+}
+
+test_expect_success 'upgrades repo format and adds extension' '
+	reset_config_when_finished &&
+	git -C base worktree init-worktree-config >out 2>err &&
+	test_must_be_empty out &&
+	test_must_be_empty err &&
+	test_cmp_config -C base 1 core.repositoryFormatVersion &&
+	test_cmp_config -C base true extensions.worktreeConfig
+'
+
+test_expect_success 'relocates core.worktree' '
+	reset_config_when_finished &&
+	mkdir dir &&
+	git -C base config core.worktree ../../dir &&
+	git -C base worktree init-worktree-config >out 2>err &&
+	test_must_be_empty out &&
+	test_must_be_empty err &&
+	test_cmp_config -C base 1 core.repositoryFormatVersion &&
+	test_cmp_config -C base true extensions.worktreeConfig &&
+	test_cmp_config -C base ../../dir core.worktree &&
+	test_must_fail git -C worktree core.worktree
+'
+
+test_expect_success 'relocates core.bare' '
+	reset_config_when_finished &&
+	git -C base config core.bare true &&
+	git -C base worktree init-worktree-config >out 2>err &&
+	test_must_be_empty out &&
+	test_must_be_empty err &&
+	test_cmp_config -C base 1 core.repositoryFormatVersion &&
+	test_cmp_config -C base true extensions.worktreeConfig &&
+	test_cmp_config -C base true core.bare &&
+	test_must_fail git -C worktree core.bare
+'
+
+test_expect_success 'skips upgrade is already upgraded' '
+	reset_config_when_finished &&
+	git -C base worktree init-worktree-config &&
+	git -C base config core.bare true &&
+
+	# this should be a no-op, even though core.bare
+	# makes the worktree be broken.
+	git -C base worktree init-worktree-config >out 2>err &&
+	test_must_be_empty out &&
+	test_must_be_empty err &&
+	test_must_fail git -C base config --worktree core.bare &&
+	git -C base config core.bare
+'
+
+test_done
-- 
gitgitgadget


  parent reply	other threads:[~2021-12-28 21:32 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
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     ` Derrick Stolee via GitGitGadget [this message]
2021-12-29  6:48       ` [PATCH v3 3/6] worktree: add 'init-worktree-config' subcommand 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

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e2a0a458115a26cfb855f7040f15e5198072b3a5.1640727143.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=allred.sean@gmail.com \
    --cc=derrickstolee@github.com \
    --cc=dstolee@microsoft.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=newren@gmail.com \
    --cc=stolee@gmail.com \
    --cc=sunshine@sunshineco.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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).