Skip to content

Commit 5325591

Browse files
derrickstoleegitster
authored andcommitted
worktree: copy sparse-checkout patterns and config on add
When adding a new worktree, it is reasonable to expect that we want to use the current set of sparse-checkout settings for that new worktree. This is particularly important for repositories where the worktree would become too large to be useful. This is even more important when using partial clone as well, since we want to avoid downloading the missing blobs for files that should not be written to the new worktree. The only way to create such a worktree without this intermediate step of expanding the full worktree is to copy the sparse-checkout patterns and config settings during 'git worktree add'. Each worktree has its own sparse-checkout patterns, and the default behavior when the sparse-checkout file is missing is to include all paths at HEAD. Thus, we need to have patterns from somewhere, they might as well be the current worktree's patterns. These are then modified independently in the future. In addition to the sparse-checkout file, copy the worktree config file if worktree config is enabled and the file exists. This will copy over any important settings to ensure the new worktree behaves the same as the current one. The only exception we must continue to make is that core.bare and core.worktree should become unset in the worktree's config file. Signed-off-by: Derrick Stolee <[email protected]> Reviewed-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7316dc5 commit 5325591

File tree

3 files changed

+142
-10
lines changed

3 files changed

+142
-10
lines changed

builtin/worktree.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,69 @@ static int add_worktree(const char *path, const char *refname,
335335
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
336336
write_file(sb.buf, "../..");
337337

338+
/*
339+
* If the current worktree has sparse-checkout enabled, then copy
340+
* the sparse-checkout patterns from the current worktree.
341+
*/
342+
if (core_apply_sparse_checkout) {
343+
char *from_file = git_pathdup("info/sparse-checkout");
344+
char *to_file = xstrfmt("%s/info/sparse-checkout",
345+
sb_repo.buf);
346+
347+
if (file_exists(from_file)) {
348+
if (safe_create_leading_directories(to_file) ||
349+
copy_file(to_file, from_file, 0666))
350+
error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
351+
from_file, to_file);
352+
}
353+
354+
free(from_file);
355+
free(to_file);
356+
}
357+
358+
/*
359+
* If we are using worktree config, then copy all current config
360+
* values from the current worktree into the new one, that way the
361+
* new worktree behaves the same as this one.
362+
*/
363+
if (repository_format_worktree_config) {
364+
char *from_file = git_pathdup("config.worktree");
365+
char *to_file = xstrfmt("%s/config.worktree",
366+
sb_repo.buf);
367+
368+
if (file_exists(from_file)) {
369+
struct config_set cs = { { 0 } };
370+
const char *core_worktree;
371+
int bare;
372+
373+
if (safe_create_leading_directories(to_file) ||
374+
copy_file(to_file, from_file, 0666)) {
375+
error(_("failed to copy worktree config from '%s' to '%s'"),
376+
from_file, to_file);
377+
goto worktree_copy_cleanup;
378+
}
379+
380+
git_configset_init(&cs);
381+
git_configset_add_file(&cs, from_file);
382+
383+
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
384+
bare &&
385+
git_config_set_multivar_in_file_gently(
386+
to_file, "core.bare", NULL, "true", 0))
387+
error(_("failed to unset 'core.bare' in '%s'"), to_file);
388+
if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
389+
git_config_set_in_file_gently(to_file,
390+
"core.worktree", NULL))
391+
error(_("failed to unset 'core.worktree' in '%s'"), to_file);
392+
393+
git_configset_clear(&cs);
394+
}
395+
396+
worktree_copy_cleanup:
397+
free(from_file);
398+
free(to_file);
399+
}
400+
338401
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
339402
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
340403
cp.git_cmd = 1;

t/t1091-sparse-checkout-builtin.sh

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ test_expect_success 'interaction with clone --no-checkout (unborn index)' '
146146
'
147147

148148
test_expect_success 'set enables config' '
149-
git init empty-config &&
149+
git init worktree-config &&
150150
(
151-
cd empty-config &&
151+
cd worktree-config &&
152152
test_commit test file &&
153153
test_path_is_missing .git/config.worktree &&
154154
git sparse-checkout set nothing &&
@@ -201,6 +201,21 @@ test_expect_success 'add to sparse-checkout' '
201201
check_files repo "a folder1 folder2"
202202
'
203203

204+
test_expect_success 'worktree: add copies sparse-checkout patterns' '
205+
cat repo/.git/info/sparse-checkout >old &&
206+
test_when_finished cp old repo/.git/info/sparse-checkout &&
207+
test_when_finished git -C repo worktree remove ../worktree &&
208+
git -C repo sparse-checkout set --no-cone "/*" &&
209+
git -C repo worktree add --quiet ../worktree 2>err &&
210+
test_must_be_empty err &&
211+
new="$(git -C worktree rev-parse --git-path info/sparse-checkout)" &&
212+
test_path_is_file "$new" &&
213+
test_cmp repo/.git/info/sparse-checkout "$new" &&
214+
git -C worktree sparse-checkout set --cone &&
215+
test_cmp_config -C worktree true core.sparseCheckoutCone &&
216+
test_must_fail git -C repo core.sparseCheckoutCone
217+
'
218+
204219
test_expect_success 'cone mode: match patterns' '
205220
git -C repo config --worktree core.sparseCheckoutCone true &&
206221
rm -rf repo/a repo/folder1 repo/folder2 &&
@@ -520,13 +535,13 @@ test_expect_success 'interaction with submodules' '
520535
'
521536

522537
test_expect_success 'different sparse-checkouts with worktrees' '
538+
git -C repo sparse-checkout set --cone deep folder1 &&
523539
git -C repo worktree add --detach ../worktree &&
524-
check_files worktree "a deep folder1 folder2" &&
525-
git -C worktree sparse-checkout init --cone &&
526-
git -C repo sparse-checkout set folder1 &&
527-
git -C worktree sparse-checkout set deep/deeper1 &&
528-
check_files repo a folder1 &&
529-
check_files worktree a deep
540+
check_files worktree "a deep folder1" &&
541+
git -C repo sparse-checkout set --cone folder1 &&
542+
git -C worktree sparse-checkout set --cone deep/deeper1 &&
543+
check_files repo "a folder1" &&
544+
check_files worktree "a deep"
530545
'
531546

532547
test_expect_success 'set using filename keeps file on-disk' '

t/t2400-worktree-add.sh

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,62 @@ test_expect_success '"add" default branch of a bare repo' '
165165
(
166166
git clone --bare . bare2 &&
167167
cd bare2 &&
168-
git worktree add ../there3 main
169-
)
168+
git worktree add ../there3 main &&
169+
cd ../there3 &&
170+
# Simple check that a Git command does not
171+
# immediately fail with the current setup
172+
git status
173+
) &&
174+
cat >expect <<-EOF &&
175+
init.t
176+
EOF
177+
ls there3 >actual &&
178+
test_cmp expect actual
179+
'
180+
181+
test_expect_success '"add" to bare repo with worktree config' '
182+
(
183+
git clone --bare . bare3 &&
184+
cd bare3 &&
185+
git config extensions.worktreeconfig true &&
186+
187+
# Add config values that are erroneous to have in
188+
# a config.worktree file outside of the main
189+
# working tree, to check that Git filters them out
190+
# when copying config during "git worktree add".
191+
git config --worktree core.bare true &&
192+
git config --worktree core.worktree "$(pwd)" &&
193+
194+
# We want to check that bogus.key is copied
195+
git config --worktree bogus.key value &&
196+
git config --unset core.bare &&
197+
git worktree add ../there4 main &&
198+
cd ../there4 &&
199+
200+
# Simple check that a Git command does not
201+
# immediately fail with the current setup
202+
git status &&
203+
git worktree add --detach ../there5 &&
204+
cd ../there5 &&
205+
git status
206+
) &&
207+
208+
# the worktree has the arbitrary value copied.
209+
test_cmp_config -C there4 value bogus.key &&
210+
test_cmp_config -C there5 value bogus.key &&
211+
212+
# however, core.bare and core.worktree were removed.
213+
test_must_fail git -C there4 config core.bare &&
214+
test_must_fail git -C there4 config core.worktree &&
215+
216+
cat >expect <<-EOF &&
217+
init.t
218+
EOF
219+
220+
ls there4 >actual &&
221+
test_cmp expect actual &&
222+
ls there5 >actual &&
223+
test_cmp expect actual
170224
'
171225

172226
test_expect_success 'checkout with grafts' '

0 commit comments

Comments
 (0)