Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2022-02-26 02:47:33 +0300
committerJunio C Hamano <gitster@pobox.com>2022-02-26 02:47:33 +0300
commit6249ce2d1b9b60e7aa630d370e68c87ef6331629 (patch)
treefafbfe509b3e197c0b1681d417d2cd1d220d8b84
parent268e6b8d4d95d9ade705666e152a4c054da32a47 (diff)
parent3ce113827287079dced9aaf9c5d1e1734ecaa265 (diff)
Merge branch 'ds/sparse-checkout-requires-per-worktree-config'
"git sparse-checkout" wants to work with per-worktree configuration, but did not work well in a worktree attached to a bare repository. * ds/sparse-checkout-requires-per-worktree-config: config: make git_configset_get_string_tmp() private worktree: copy sparse-checkout patterns and config on add sparse-checkout: set worktree-config correctly config: add repo_config_set_worktree_gently() worktree: create init_worktree_config() Documentation: add extensions.worktreeConfig details
-rw-r--r--Documentation/config/extensions.txt31
-rw-r--r--Documentation/git-config.txt8
-rw-r--r--Documentation/git-sparse-checkout.txt16
-rw-r--r--Documentation/git-worktree.txt11
-rw-r--r--builtin/sparse-checkout.c28
-rw-r--r--builtin/worktree.c63
-rw-r--r--config.c39
-rw-r--r--config.h9
-rw-r--r--sparse-index.c10
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh35
-rwxr-xr-xt/t2400-worktree-add.sh58
-rw-r--r--worktree.c73
-rw-r--r--worktree.h21
13 files changed, 353 insertions, 49 deletions
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
index 4e23d73cdc..bccaec7a96 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.txt
@@ -6,3 +6,34 @@ extensions.objectFormat::
Note that this setting should only be set by linkgit:git-init[1] or
linkgit:git-clone[1]. Trying to change it after initialization will not
work and will produce hard-to-diagnose issues.
+
+extensions.worktreeConfig::
+ If enabled, then worktrees will load config settings from the
+ `$GIT_DIR/config.worktree` file in addition to the
+ `$GIT_COMMON_DIR/config` file. Note that `$GIT_COMMON_DIR` and
+ `$GIT_DIR` are the same for the main working tree, while other
+ working trees have `$GIT_DIR` equal to
+ `$GIT_COMMON_DIR/worktrees/<id>/`. The settings in the
+ `config.worktree` file will override settings from any other
+ config files.
++
+When enabling `extensions.worktreeConfig`, you must be careful to move
+certain values from the common config file to the main working tree's
+`config.worktree` file, if present:
++
+* `core.worktree` must be moved from `$GIT_COMMON_DIR/config` to
+ `$GIT_COMMON_DIR/config.worktree`.
+* If `core.bare` is true, then it must be moved from `$GIT_COMMON_DIR/config`
+ to `$GIT_COMMON_DIR/config.worktree`.
++
+It may also be beneficial to adjust the locations of `core.sparseCheckout`
+and `core.sparseCheckoutCone` depending on your desire for customizable
+sparse-checkout settings for each worktree. By default, the `git
+sparse-checkout` builtin enables `extensions.worktreeConfig`, assigns
+these config values on a per-worktree basis, and uses the
+`$GIT_DIR/info/sparse-checkout` file to specify the sparsity for each
+worktree independently. See linkgit:git-sparse-checkout[1] for more
+details.
++
+For historical reasons, `extensions.worktreeConfig` is respected
+regardless of the `core.repositoryFormatVersion` setting.
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 2285effb36..bdcfd94b64 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -141,9 +141,13 @@ from all available files.
See also <<FILES>>.
--worktree::
- Similar to `--local` except that `.git/config.worktree` is
+ Similar to `--local` except that `$GIT_DIR/config.worktree` is
read from or written to if `extensions.worktreeConfig` is
- present. If not it's the same as `--local`.
+ enabled. If not it's the same as `--local`. Note that `$GIT_DIR`
+ is equal to `$GIT_COMMON_DIR` for the main working tree, but is of
+ the form `$GIT_DIR/worktrees/<id>/` for other working trees. See
+ linkgit:git-worktree[1] to learn how to enable
+ `extensions.worktreeConfig`.
-f <config-file>::
--file <config-file>::
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index b81dbe0654..94dad137b9 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -31,13 +31,21 @@ COMMANDS
Describe the patterns in the sparse-checkout file.
'set'::
- Enable the necessary config settings
- (extensions.worktreeConfig, core.sparseCheckout,
- core.sparseCheckoutCone) if they are not already enabled, and
- write a set of patterns to the sparse-checkout file from the
+ Enable the necessary sparse-checkout config settings
+ (`core.sparseCheckout`, `core.sparseCheckoutCone`, and
+ `index.sparse`) if they are not already set to the desired values,
+ and write a set of patterns to the sparse-checkout file from the
list of arguments following the 'set' subcommand. Update the
working directory to match the new patterns.
+
+To ensure that adjusting the sparse-checkout settings within a worktree
+does not alter the sparse-checkout settings in other worktrees, the 'set'
+subcommand will upgrade your repository config to use worktree-specific
+config if not already present. The sparsity defined by the arguments to
+the 'set' subcommand are stored in the worktree-specific sparse-checkout
+file. See linkgit:git-worktree[1] and the documentation of
+`extensions.worktreeConfig` in linkgit:git-config[1] for more details.
++
When the `--stdin` option is provided, the patterns are read from
standard in as a newline-delimited list instead of from the arguments.
+
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 9e862fbcf7..b8d53c4830 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -286,8 +286,8 @@ CONFIGURATION FILE
------------------
By default, the repository `config` file is shared across all working
trees. If the config variables `core.bare` or `core.worktree` are
-already present in the config file, they will be applied to the main
-working trees only.
+present in the common config file and `extensions.worktreeConfig` is
+disabled, then they will be applied to the main working tree only.
In order to have configuration specific to working trees, you can turn
on the `worktreeConfig` extension, e.g.:
@@ -307,11 +307,16 @@ 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:
- - `core.worktree` and `core.bare` should never be shared
+ - `core.worktree` should never be shared.
+
+ - `core.bare` should not be shared if the value is `core.bare=true`.
- `core.sparseCheckout` is recommended per working tree, unless you
are sure you always use sparse checkout for all working trees.
+See the documentation of `extensions.worktreeConfig` in
+linkgit:git-config[1] for more details.
+
DETAILS
-------
Each linked working tree has a private sub-directory in the repository's
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index a311483a7d..f2356554e5 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -15,6 +15,7 @@
#include "wt-status.h"
#include "quote.h"
#include "sparse-index.h"
+#include "worktree.h"
static const char *empty_base = "";
@@ -361,26 +362,23 @@ enum sparse_checkout_mode {
static int set_config(enum sparse_checkout_mode mode)
{
- const char *config_path;
-
- if (upgrade_repository_format(1) < 0)
- die(_("unable to upgrade repository format to enable worktreeConfig"));
- if (git_config_set_gently("extensions.worktreeConfig", "true")) {
- error(_("failed to set extensions.worktreeConfig setting"));
+ /* Update to use worktree config, if not already. */
+ if (init_worktree_config(the_repository)) {
+ error(_("failed to initialize worktree config"));
return 1;
}
- config_path = git_path("config.worktree");
- git_config_set_in_file_gently(config_path,
- "core.sparseCheckout",
- mode ? "true" : NULL);
-
- git_config_set_in_file_gently(config_path,
- "core.sparseCheckoutCone",
- mode == MODE_CONE_PATTERNS ? "true" : NULL);
+ if (repo_config_set_worktree_gently(the_repository,
+ "core.sparseCheckout",
+ mode ? "true" : "false") ||
+ repo_config_set_worktree_gently(the_repository,
+ "core.sparseCheckoutCone",
+ mode == MODE_CONE_PATTERNS ?
+ "true" : "false"))
+ return 1;
if (mode == MODE_NO_PATTERNS)
- set_sparse_index_config(the_repository, 0);
+ return set_sparse_index_config(the_repository, 0);
return 0;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 0d0809276f..e23e6343d0 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -335,6 +335,69 @@ static int add_worktree(const char *path, const char *refname,
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
+ /*
+ * If the current worktree has sparse-checkout enabled, then copy
+ * the sparse-checkout patterns from the current worktree.
+ */
+ if (core_apply_sparse_checkout) {
+ char *from_file = git_pathdup("info/sparse-checkout");
+ char *to_file = xstrfmt("%s/info/sparse-checkout",
+ sb_repo.buf);
+
+ if (file_exists(from_file)) {
+ if (safe_create_leading_directories(to_file) ||
+ copy_file(to_file, from_file, 0666))
+ error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
+ from_file, to_file);
+ }
+
+ free(from_file);
+ free(to_file);
+ }
+
+ /*
+ * If we are using worktree config, then copy all current config
+ * values from the current worktree into the new one, that way the
+ * new worktree behaves the same as this one.
+ */
+ if (repository_format_worktree_config) {
+ char *from_file = git_pathdup("config.worktree");
+ char *to_file = xstrfmt("%s/config.worktree",
+ sb_repo.buf);
+
+ if (file_exists(from_file)) {
+ struct config_set cs = { { 0 } };
+ const char *core_worktree;
+ int bare;
+
+ if (safe_create_leading_directories(to_file) ||
+ copy_file(to_file, from_file, 0666)) {
+ error(_("failed to copy worktree config from '%s' to '%s'"),
+ from_file, to_file);
+ goto worktree_copy_cleanup;
+ }
+
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, from_file);
+
+ if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
+ bare &&
+ git_config_set_multivar_in_file_gently(
+ to_file, "core.bare", NULL, "true", 0))
+ error(_("failed to unset 'core.bare' in '%s'"), to_file);
+ if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
+ git_config_set_in_file_gently(to_file,
+ "core.worktree", NULL))
+ error(_("failed to unset 'core.worktree' in '%s'"), to_file);
+
+ git_configset_clear(&cs);
+ }
+
+worktree_copy_cleanup:
+ free(from_file);
+ free(to_file);
+ }
+
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
cp.git_cmd = 1;
diff --git a/config.c b/config.c
index e0c03d154c..be4cd2d353 100644
--- a/config.c
+++ b/config.c
@@ -21,6 +21,7 @@
#include "dir.h"
#include "color.h"
#include "refs.h"
+#include "worktree.h"
struct config_source {
struct config_source *prev;
@@ -2294,8 +2295,8 @@ int git_configset_get_string(struct config_set *cs, const char *key, char **dest
return 1;
}
-int git_configset_get_string_tmp(struct config_set *cs, const char *key,
- const char **dest)
+static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+ const char **dest)
{
const char *value;
if (!git_configset_get_value(cs, key, &value)) {
@@ -3000,6 +3001,20 @@ int git_config_set_gently(const char *key, const char *value)
return git_config_set_multivar_gently(key, value, NULL, 0);
}
+int repo_config_set_worktree_gently(struct repository *r,
+ const char *key, const char *value)
+{
+ /* Only use worktree-specific config if it is is already enabled. */
+ if (repository_format_worktree_config) {
+ char *file = repo_git_path(r, "config.worktree");
+ int ret = git_config_set_multivar_in_file_gently(
+ file, key, value, NULL, 0);
+ free(file);
+ return ret;
+ }
+ return repo_config_set_multivar_gently(r, key, value, NULL, 0);
+}
+
void git_config_set(const char *key, const char *value)
{
git_config_set_multivar(key, value, NULL, 0);
@@ -3297,14 +3312,28 @@ void git_config_set_multivar_in_file(const char *config_filename,
int git_config_set_multivar_gently(const char *key, const char *value,
const char *value_pattern, unsigned flags)
{
- return git_config_set_multivar_in_file_gently(NULL, key, value, value_pattern,
- flags);
+ return repo_config_set_multivar_gently(the_repository, key, value,
+ value_pattern, flags);
+}
+
+int repo_config_set_multivar_gently(struct repository *r, const char *key,
+ const char *value,
+ const char *value_pattern, unsigned flags)
+{
+ char *file = repo_git_path(r, "config");
+ int res = git_config_set_multivar_in_file_gently(file,
+ key, value,
+ value_pattern,
+ flags);
+ free(file);
+ return res;
}
void git_config_set_multivar(const char *key, const char *value,
const char *value_pattern, unsigned flags)
{
- git_config_set_multivar_in_file(NULL, key, value, value_pattern,
+ git_config_set_multivar_in_file(git_path("config"),
+ key, value, value_pattern,
flags);
}
diff --git a/config.h b/config.h
index ab0106d287..bb49baf1ee 100644
--- a/config.h
+++ b/config.h
@@ -267,6 +267,13 @@ void git_config_set_in_file(const char *, const char *, const char *);
int git_config_set_gently(const char *, const char *);
/**
+ * Write a config value that should apply to the current worktree. If
+ * extensions.worktreeConfig is enabled, then the write will happen in the
+ * current worktree's config. Otherwise, write to the common config file.
+ */
+int repo_config_set_worktree_gently(struct repository *, const char *, const char *);
+
+/**
* write config values to `.git/config`, takes a key/value pair as parameter.
*/
void git_config_set(const char *, const char *);
@@ -294,6 +301,7 @@ int git_config_parse_key(const char *, char **, size_t *);
int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
void git_config_set_multivar(const char *, const char *, const char *, unsigned);
+int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, unsigned);
/**
@@ -466,7 +474,6 @@ void git_configset_clear(struct config_set *cs);
int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
-int git_configset_get_string_tmp(struct config_set *cs, const char *key, const char **dest);
int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
diff --git a/sparse-index.c b/sparse-index.c
index 08f54747bb..fdbe97b976 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -99,13 +99,9 @@ static int convert_to_sparse_rec(struct index_state *istate,
int set_sparse_index_config(struct repository *repo, int enable)
{
- int res;
- char *config_path = repo_git_path(repo, "config.worktree");
- res = git_config_set_in_file_gently(config_path,
- "index.sparse",
- enable ? "true" : NULL);
- free(config_path);
-
+ int res = repo_config_set_worktree_gently(repo,
+ "index.sparse",
+ enable ? "true" : "false");
prepare_repo_settings(repo);
repo->settings.sparse_index = enable;
return res;
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 3592d12442..502d42d183 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -126,7 +126,7 @@ test_expect_success 'switching to cone mode with non-cone mode patterns' '
cd bad-patterns &&
git sparse-checkout init &&
git sparse-checkout add dir &&
- git config core.sparseCheckoutCone true &&
+ git config --worktree core.sparseCheckoutCone true &&
test_must_fail git sparse-checkout add dir 2>err &&
grep "existing sparse-checkout patterns do not use cone mode" err
)
@@ -155,9 +155,9 @@ test_expect_success 'interaction with clone --no-checkout (unborn index)' '
'
test_expect_success 'set enables config' '
- git init empty-config &&
+ git init worktree-config &&
(
- cd empty-config &&
+ cd worktree-config &&
test_commit test file &&
test_path_is_missing .git/config.worktree &&
git sparse-checkout set nothing &&
@@ -210,6 +210,21 @@ test_expect_success 'add to sparse-checkout' '
check_files repo "a folder1 folder2"
'
+test_expect_success 'worktree: add copies sparse-checkout patterns' '
+ cat repo/.git/info/sparse-checkout >old &&
+ test_when_finished cp old repo/.git/info/sparse-checkout &&
+ test_when_finished git -C repo worktree remove ../worktree &&
+ git -C repo sparse-checkout set --no-cone "/*" &&
+ git -C repo worktree add --quiet ../worktree 2>err &&
+ test_must_be_empty err &&
+ new="$(git -C worktree rev-parse --git-path info/sparse-checkout)" &&
+ test_path_is_file "$new" &&
+ test_cmp repo/.git/info/sparse-checkout "$new" &&
+ git -C worktree sparse-checkout set --cone &&
+ test_cmp_config -C worktree true core.sparseCheckoutCone &&
+ test_must_fail git -C repo core.sparseCheckoutCone
+'
+
test_expect_success 'cone mode: match patterns' '
git -C repo config --worktree core.sparseCheckoutCone true &&
rm -rf repo/a repo/folder1 repo/folder2 &&
@@ -261,7 +276,7 @@ test_expect_success 'sparse-index enabled and disabled' '
test_cmp expect actual &&
git -C repo config --list >config &&
- ! grep index.sparse config
+ test_cmp_config -C repo false index.sparse
'
test_expect_success 'cone mode: init and set' '
@@ -524,13 +539,13 @@ test_expect_success 'interaction with submodules' '
'
test_expect_success 'different sparse-checkouts with worktrees' '
+ git -C repo sparse-checkout set --cone deep folder1 &&
git -C repo worktree add --detach ../worktree &&
- check_files worktree "a deep folder1 folder2" &&
- git -C worktree sparse-checkout init --cone &&
- git -C repo sparse-checkout set folder1 &&
- git -C worktree sparse-checkout set deep/deeper1 &&
- check_files repo a folder1 &&
- check_files worktree a deep
+ check_files worktree "a deep folder1" &&
+ git -C repo sparse-checkout set --cone folder1 &&
+ git -C worktree sparse-checkout set --cone deep/deeper1 &&
+ check_files repo "a folder1" &&
+ check_files worktree "a deep"
'
test_expect_success 'set using filename keeps file on-disk' '
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 37ad79470f..43139af08f 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -165,8 +165,62 @@ test_expect_success '"add" default branch of a bare repo' '
(
git clone --bare . bare2 &&
cd bare2 &&
- git worktree add ../there3 main
- )
+ git worktree add ../there3 main &&
+ cd ../there3 &&
+ # Simple check that a Git command does not
+ # immediately fail with the current setup
+ git status
+ ) &&
+ cat >expect <<-EOF &&
+ init.t
+ EOF
+ ls there3 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '"add" to bare repo with worktree config' '
+ (
+ git clone --bare . bare3 &&
+ cd bare3 &&
+ git config extensions.worktreeconfig true &&
+
+ # Add config values that are erroneous to have in
+ # a config.worktree file outside of the main
+ # working tree, to check that Git filters them out
+ # when copying config during "git worktree add".
+ git config --worktree core.bare true &&
+ git config --worktree core.worktree "$(pwd)" &&
+
+ # We want to check that bogus.key is copied
+ git config --worktree bogus.key value &&
+ git config --unset core.bare &&
+ git worktree add ../there4 main &&
+ cd ../there4 &&
+
+ # Simple check that a Git command does not
+ # immediately fail with the current setup
+ git status &&
+ git worktree add --detach ../there5 &&
+ cd ../there5 &&
+ git status
+ ) &&
+
+ # the worktree has the arbitrary value copied.
+ test_cmp_config -C there4 value bogus.key &&
+ test_cmp_config -C there5 value bogus.key &&
+
+ # however, core.bare and core.worktree were removed.
+ test_must_fail git -C there4 config core.bare &&
+ test_must_fail git -C there4 config core.worktree &&
+
+ cat >expect <<-EOF &&
+ init.t
+ EOF
+
+ ls there4 >actual &&
+ test_cmp expect actual &&
+ ls there5 >actual &&
+ test_cmp expect actual
'
test_expect_success 'checkout with grafts' '
diff --git a/worktree.c b/worktree.c
index e8f6f6ae6f..90fc085f76 100644
--- a/worktree.c
+++ b/worktree.c
@@ -5,6 +5,7 @@
#include "worktree.h"
#include "dir.h"
#include "wt-status.h"
+#include "config.h"
void free_worktrees(struct worktree **worktrees)
{
@@ -821,3 +822,75 @@ int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath,
*wtpath = path;
return 0;
}
+
+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;
+}
+
+int init_worktree_config(struct repository *r)
+{
+ int res = 0;
+ int bare = 0;
+ struct config_set cs = { { 0 } };
+ const char *core_worktree;
+ char *common_config_file;
+ char *main_worktree_file;
+
+ /*
+ * If the extension is already enabled, then we can skip the
+ * upgrade process.
+ */
+ if (repository_format_worktree_config)
+ return 0;
+ if ((res = git_config_set_gently("extensions.worktreeConfig", "true")))
+ return error(_("failed to set extensions.worktreeConfig setting"));
+
+ common_config_file = xstrfmt("%s/config", r->commondir);
+ main_worktree_file = xstrfmt("%s/config.worktree", r->commondir);
+
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, common_config_file);
+
+ /*
+ * If core.bare is true in the common config file, then we need to
+ * move it to the main 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 main 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_value(&cs, "core.worktree", &core_worktree)) {
+ if ((res = move_config_setting("core.worktree", core_worktree,
+ common_config_file,
+ main_worktree_file)))
+ goto cleanup;
+ }
+
+ /*
+ * Ensure that we use worktree config for the remaining lifetime
+ * of the current process.
+ */
+ repository_format_worktree_config = 1;
+
+cleanup:
+ git_configset_clear(&cs);
+ free(common_config_file);
+ free(main_worktree_file);
+ return res;
+}
diff --git a/worktree.h b/worktree.h
index 9e06fcbdf3..e9e839926b 100644
--- a/worktree.h
+++ b/worktree.h
@@ -183,4 +183,25 @@ void strbuf_worktree_ref(const struct worktree *wt,
struct strbuf *sb,
const char *refname);
+/**
+ * Enable worktree config for the first time. This will make the following
+ * adjustments:
+ *
+ * 1. Add extensions.worktreeConfig=true in the common config file.
+ *
+ * 2. If the common config file has a core.worktree value, then that value
+ * is moved to the main worktree's config.worktree file.
+ *
+ * 3. If the common config file has a core.bare enabled, then that value
+ * is moved to the main worktree's config.worktree file.
+ *
+ * If extensions.worktreeConfig is already true, then this method
+ * terminates early without any of the above steps. The existing config
+ * arrangement is assumed to be intentional.
+ *
+ * Returns 0 on success. Reports an error message and returns non-zero
+ * if any of these steps fail.
+ */
+int init_worktree_config(struct repository *r);
+
#endif