Skip to content

Commit 615a84a

Browse files
derrickstoleegitster
authored andcommitted
worktree: create init_worktree_config()
Upgrading a repository to use extensions.worktreeConfig is non-trivial. There are several steps involved, including moving some config settings from the common config file to the main worktree's config.worktree file. The previous change updated the documentation with all of these details. Commands such as 'git sparse-checkout set' upgrade the repository to use extensions.worktreeConfig without following these steps, causing some user pain in some special cases. Create a helper method, init_worktree_config(), that will be used in a later change to fix this behavior within 'git sparse-checkout set'. The method is carefully documented in worktree.h. Note that we do _not_ upgrade the repository format version to 1 during this process. The worktree config extension must be considered by Git and third-party tools even if core.repositoryFormatVersion is 0 for historical reasons documented in 1166419 ("Revert "check_repository_format_gently(): refuse extensions for old repositories"", 2020-07-15). This is a special case for this extension, and newer extensions (such as extensions.objectFormat) still need to upgrade the repository format version. Signed-off-by: Derrick Stolee <[email protected]> Reviewed-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5c11c0d commit 615a84a

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

worktree.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "worktree.h"
66
#include "dir.h"
77
#include "wt-status.h"
8+
#include "config.h"
89

910
void free_worktrees(struct worktree **worktrees)
1011
{
@@ -826,3 +827,75 @@ int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath,
826827
*wtpath = path;
827828
return 0;
828829
}
830+
831+
static int move_config_setting(const char *key, const char *value,
832+
const char *from_file, const char *to_file)
833+
{
834+
if (git_config_set_in_file_gently(to_file, key, value))
835+
return error(_("unable to set %s in '%s'"), key, to_file);
836+
if (git_config_set_in_file_gently(from_file, key, NULL))
837+
return error(_("unable to unset %s in '%s'"), key, from_file);
838+
return 0;
839+
}
840+
841+
int init_worktree_config(struct repository *r)
842+
{
843+
int res = 0;
844+
int bare = 0;
845+
struct config_set cs = { { 0 } };
846+
const char *core_worktree;
847+
char *common_config_file;
848+
char *main_worktree_file;
849+
850+
/*
851+
* If the extension is already enabled, then we can skip the
852+
* upgrade process.
853+
*/
854+
if (repository_format_worktree_config)
855+
return 0;
856+
if ((res = git_config_set_gently("extensions.worktreeConfig", "true")))
857+
return error(_("failed to set extensions.worktreeConfig setting"));
858+
859+
common_config_file = xstrfmt("%s/config", r->commondir);
860+
main_worktree_file = xstrfmt("%s/config.worktree", r->commondir);
861+
862+
git_configset_init(&cs);
863+
git_configset_add_file(&cs, common_config_file);
864+
865+
/*
866+
* If core.bare is true in the common config file, then we need to
867+
* move it to the main worktree's config file or it will break all
868+
* worktrees. If it is false, then leave it in place because it
869+
* _could_ be negating a global core.bare=true.
870+
*/
871+
if (!git_configset_get_bool(&cs, "core.bare", &bare) && bare) {
872+
if ((res = move_config_setting("core.bare", "true",
873+
common_config_file,
874+
main_worktree_file)))
875+
goto cleanup;
876+
}
877+
/*
878+
* If core.worktree is set, then the main worktree is located
879+
* somewhere different than the parent of the common Git dir.
880+
* Relocate that value to avoid breaking all worktrees with this
881+
* upgrade to worktree config.
882+
*/
883+
if (!git_configset_get_value(&cs, "core.worktree", &core_worktree)) {
884+
if ((res = move_config_setting("core.worktree", core_worktree,
885+
common_config_file,
886+
main_worktree_file)))
887+
goto cleanup;
888+
}
889+
890+
/*
891+
* Ensure that we use worktree config for the remaining lifetime
892+
* of the current process.
893+
*/
894+
repository_format_worktree_config = 1;
895+
896+
cleanup:
897+
git_configset_clear(&cs);
898+
free(common_config_file);
899+
free(main_worktree_file);
900+
return res;
901+
}

worktree.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,25 @@ void strbuf_worktree_ref(const struct worktree *wt,
183183
struct strbuf *sb,
184184
const char *refname);
185185

186+
/**
187+
* Enable worktree config for the first time. This will make the following
188+
* adjustments:
189+
*
190+
* 1. Add extensions.worktreeConfig=true in the common config file.
191+
*
192+
* 2. If the common config file has a core.worktree value, then that value
193+
* is moved to the main worktree's config.worktree file.
194+
*
195+
* 3. If the common config file has a core.bare enabled, then that value
196+
* is moved to the main worktree's config.worktree file.
197+
*
198+
* If extensions.worktreeConfig is already true, then this method
199+
* terminates early without any of the above steps. The existing config
200+
* arrangement is assumed to be intentional.
201+
*
202+
* Returns 0 on success. Reports an error message and returns non-zero
203+
* if any of these steps fail.
204+
*/
205+
int init_worktree_config(struct repository *r);
206+
186207
#endif

0 commit comments

Comments
 (0)