Merge branch 'en/sparse-checkout-fixes'
Further polishing of "git sparse-checkout". * en/sparse-checkout-fixes: sparse-checkout: reject arguments in cone-mode that look like patterns sparse-checkout: error or warn when given individual files sparse-checkout: pay attention to prefix for {set, add} sparse-checkout: correctly set non-cone mode when expected sparse-checkout: correct reapply's handling of options
This commit is contained in:
commit
967176465a
@ -1,4 +1,5 @@
|
|||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "cache.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
@ -401,6 +402,7 @@ static int update_modes(int *cone_mode, int *sparse_index)
|
|||||||
core_sparse_checkout_cone = 1;
|
core_sparse_checkout_cone = 1;
|
||||||
} else {
|
} else {
|
||||||
mode = MODE_ALL_PATTERNS;
|
mode = MODE_ALL_PATTERNS;
|
||||||
|
core_sparse_checkout_cone = 0;
|
||||||
}
|
}
|
||||||
if (record_mode && set_config(mode))
|
if (record_mode && set_config(mode))
|
||||||
return 1;
|
return 1;
|
||||||
@ -681,18 +683,76 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sanitize_paths(int argc, const char **argv,
|
||||||
|
const char *prefix, int skip_checks)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (prefix && *prefix && core_sparse_checkout_cone) {
|
||||||
|
/*
|
||||||
|
* The args are not pathspecs, so unfortunately we
|
||||||
|
* cannot imitate how cmd_add() uses parse_pathspec().
|
||||||
|
*/
|
||||||
|
int prefix_len = strlen(prefix);
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
argv[i] = prefix_path(prefix, prefix_len, argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip_checks)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (prefix && *prefix && !core_sparse_checkout_cone)
|
||||||
|
die(_("please run from the toplevel directory in non-cone mode"));
|
||||||
|
|
||||||
|
if (core_sparse_checkout_cone) {
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (argv[i][0] == '/')
|
||||||
|
die(_("specify directories rather than patterns (no leading slash)"));
|
||||||
|
if (argv[i][0] == '!')
|
||||||
|
die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
|
||||||
|
if (strpbrk(argv[i], "*?[]"))
|
||||||
|
die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
struct cache_entry *ce;
|
||||||
|
struct index_state *index = the_repository->index;
|
||||||
|
int pos = index_name_pos(index, argv[i], strlen(argv[i]));
|
||||||
|
|
||||||
|
if (pos < 0)
|
||||||
|
continue;
|
||||||
|
ce = index->cache[pos];
|
||||||
|
if (S_ISSPARSEDIR(ce->ce_mode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (core_sparse_checkout_cone)
|
||||||
|
die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), argv[i]);
|
||||||
|
else
|
||||||
|
warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char const * const builtin_sparse_checkout_add_usage[] = {
|
static char const * const builtin_sparse_checkout_add_usage[] = {
|
||||||
N_("git sparse-checkout add (--stdin | <patterns>)"),
|
N_("git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sparse_checkout_add_opts {
|
static struct sparse_checkout_add_opts {
|
||||||
|
int skip_checks;
|
||||||
int use_stdin;
|
int use_stdin;
|
||||||
} add_opts;
|
} add_opts;
|
||||||
|
|
||||||
static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
|
static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
static struct option builtin_sparse_checkout_add_options[] = {
|
static struct option builtin_sparse_checkout_add_options[] = {
|
||||||
|
OPT_BOOL_F(0, "skip-checks", &add_opts.skip_checks,
|
||||||
|
N_("skip some sanity checks on the given paths that might give false positives"),
|
||||||
|
PARSE_OPT_NONEG),
|
||||||
OPT_BOOL(0, "stdin", &add_opts.use_stdin,
|
OPT_BOOL(0, "stdin", &add_opts.use_stdin,
|
||||||
N_("read patterns from standard in")),
|
N_("read patterns from standard in")),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
@ -708,17 +768,20 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
|
|||||||
builtin_sparse_checkout_add_usage,
|
builtin_sparse_checkout_add_usage,
|
||||||
PARSE_OPT_KEEP_UNKNOWN);
|
PARSE_OPT_KEEP_UNKNOWN);
|
||||||
|
|
||||||
|
sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
|
||||||
|
|
||||||
return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
|
return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const * const builtin_sparse_checkout_set_usage[] = {
|
static char const * const builtin_sparse_checkout_set_usage[] = {
|
||||||
N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] (--stdin | <patterns>)"),
|
N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] (--stdin | <patterns>)"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sparse_checkout_set_opts {
|
static struct sparse_checkout_set_opts {
|
||||||
int cone_mode;
|
int cone_mode;
|
||||||
int sparse_index;
|
int sparse_index;
|
||||||
|
int skip_checks;
|
||||||
int use_stdin;
|
int use_stdin;
|
||||||
} set_opts;
|
} set_opts;
|
||||||
|
|
||||||
@ -732,6 +795,9 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
|
|||||||
N_("initialize the sparse-checkout in cone mode")),
|
N_("initialize the sparse-checkout in cone mode")),
|
||||||
OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
|
OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
|
||||||
N_("toggle the use of a sparse index")),
|
N_("toggle the use of a sparse index")),
|
||||||
|
OPT_BOOL_F(0, "skip-checks", &set_opts.skip_checks,
|
||||||
|
N_("skip some sanity checks on the given paths that might give false positives"),
|
||||||
|
PARSE_OPT_NONEG),
|
||||||
OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
|
OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
|
||||||
N_("read patterns from standard in"),
|
N_("read patterns from standard in"),
|
||||||
PARSE_OPT_NONEG),
|
PARSE_OPT_NONEG),
|
||||||
@ -759,6 +825,8 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
|
|||||||
if (!core_sparse_checkout_cone && argc == 0) {
|
if (!core_sparse_checkout_cone && argc == 0) {
|
||||||
argv = default_patterns;
|
argv = default_patterns;
|
||||||
argc = default_patterns_nr;
|
argc = default_patterns_nr;
|
||||||
|
} else {
|
||||||
|
sanitize_paths(argc, argv, prefix, set_opts.skip_checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
|
return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
|
||||||
@ -787,15 +855,15 @@ static int sparse_checkout_reapply(int argc, const char **argv)
|
|||||||
if (!core_apply_sparse_checkout)
|
if (!core_apply_sparse_checkout)
|
||||||
die(_("must be in a sparse-checkout to reapply sparsity patterns"));
|
die(_("must be in a sparse-checkout to reapply sparsity patterns"));
|
||||||
|
|
||||||
|
reapply_opts.cone_mode = -1;
|
||||||
|
reapply_opts.sparse_index = -1;
|
||||||
|
|
||||||
argc = parse_options(argc, argv, NULL,
|
argc = parse_options(argc, argv, NULL,
|
||||||
builtin_sparse_checkout_reapply_options,
|
builtin_sparse_checkout_reapply_options,
|
||||||
builtin_sparse_checkout_reapply_usage, 0);
|
builtin_sparse_checkout_reapply_usage, 0);
|
||||||
|
|
||||||
repo_read_index(the_repository);
|
repo_read_index(the_repository);
|
||||||
|
|
||||||
reapply_opts.cone_mode = -1;
|
|
||||||
reapply_opts.sparse_index = -1;
|
|
||||||
|
|
||||||
if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index))
|
if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -510,6 +510,37 @@ test_expect_failure 'sparse-checkout reapply' '
|
|||||||
git -C tweak sparse-checkout disable
|
git -C tweak sparse-checkout disable
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reapply can handle config options' '
|
||||||
|
git -C repo sparse-checkout init --cone --no-sparse-index &&
|
||||||
|
git -C repo config --worktree --list >actual &&
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
core.sparsecheckout=true
|
||||||
|
core.sparsecheckoutcone=true
|
||||||
|
index.sparse=false
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C repo sparse-checkout reapply --no-cone --no-sparse-index &&
|
||||||
|
git -C repo config --worktree --list >actual &&
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
core.sparsecheckout=true
|
||||||
|
core.sparsecheckoutcone=false
|
||||||
|
index.sparse=false
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C repo sparse-checkout reapply --cone --sparse-index &&
|
||||||
|
git -C repo config --worktree --list >actual &&
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
core.sparsecheckout=true
|
||||||
|
core.sparsecheckoutcone=true
|
||||||
|
index.sparse=true
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git -C repo sparse-checkout disable
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'cone mode: set with core.ignoreCase=true' '
|
test_expect_success 'cone mode: set with core.ignoreCase=true' '
|
||||||
rm repo/.git/info/sparse-checkout &&
|
rm repo/.git/info/sparse-checkout &&
|
||||||
git -C repo sparse-checkout init --cone &&
|
git -C repo sparse-checkout init --cone &&
|
||||||
@ -549,7 +580,7 @@ test_expect_success 'different sparse-checkouts with worktrees' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'set using filename keeps file on-disk' '
|
test_expect_success 'set using filename keeps file on-disk' '
|
||||||
git -C repo sparse-checkout set a deep &&
|
git -C repo sparse-checkout set --skip-checks a deep &&
|
||||||
cat >expect <<-\EOF &&
|
cat >expect <<-\EOF &&
|
||||||
/*
|
/*
|
||||||
!/*/
|
!/*/
|
||||||
@ -660,7 +691,7 @@ test_expect_success BSLASHPSPEC 'pattern-checks: escaped characters' '
|
|||||||
git -C escaped reset --hard $COMMIT &&
|
git -C escaped reset --hard $COMMIT &&
|
||||||
check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" zglob[!a]? &&
|
check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" zglob[!a]? &&
|
||||||
git -C escaped sparse-checkout init --cone &&
|
git -C escaped sparse-checkout init --cone &&
|
||||||
git -C escaped sparse-checkout set zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" "zglob[!a]?" &&
|
git -C escaped sparse-checkout set --skip-checks zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" "zglob[!a]?" &&
|
||||||
cat >expect <<-\EOF &&
|
cat >expect <<-\EOF &&
|
||||||
/*
|
/*
|
||||||
!/*/
|
!/*/
|
||||||
@ -785,4 +816,59 @@ test_expect_success 'malformed cone-mode patterns' '
|
|||||||
grep "warning: disabling cone pattern matching" err
|
grep "warning: disabling cone pattern matching" err
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set from subdir pays attention to prefix' '
|
||||||
|
git -C repo sparse-checkout disable &&
|
||||||
|
git -C repo/deep sparse-checkout set --cone deeper2 ../folder1 &&
|
||||||
|
|
||||||
|
git -C repo sparse-checkout list >actual &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
deep/deeper2
|
||||||
|
folder1
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'add from subdir pays attention to prefix' '
|
||||||
|
git -C repo sparse-checkout set --cone deep/deeper2 &&
|
||||||
|
git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 &&
|
||||||
|
|
||||||
|
git -C repo sparse-checkout list >actual &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
deep/deeper1/deepest
|
||||||
|
deep/deeper2
|
||||||
|
folder1
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set from subdir in non-cone mode throws an error' '
|
||||||
|
git -C repo sparse-checkout disable &&
|
||||||
|
test_must_fail git -C repo/deep sparse-checkout set --no-cone deeper2 ../folder1 2>error &&
|
||||||
|
|
||||||
|
grep "run from the toplevel directory in non-cone mode" error
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'set from subdir in non-cone mode throws an error' '
|
||||||
|
git -C repo sparse-checkout set --no-cone deep/deeper2 &&
|
||||||
|
test_must_fail git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 2>error &&
|
||||||
|
|
||||||
|
grep "run from the toplevel directory in non-cone mode" error
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'by default, cone mode will error out when passed files' '
|
||||||
|
git -C repo sparse-checkout reapply --cone &&
|
||||||
|
test_must_fail git -C repo sparse-checkout add .gitignore 2>error &&
|
||||||
|
|
||||||
|
grep ".gitignore.*is not a directory" error
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'by default, non-cone mode will warn on individual files' '
|
||||||
|
git -C repo sparse-checkout reapply --no-cone &&
|
||||||
|
git -C repo sparse-checkout add .gitignore 2>warning &&
|
||||||
|
|
||||||
|
grep "pass a leading slash before paths.*if you want a single file" warning
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user