Merge branch 'ds/sparse-cone'
Management of sparsely checked-out working tree has gained a dedicated "sparse-checkout" command. * ds/sparse-cone: (21 commits) sparse-checkout: improve OS ls compatibility sparse-checkout: respect core.ignoreCase in cone mode sparse-checkout: check for dirty status sparse-checkout: update working directory in-process for 'init' sparse-checkout: cone mode should not interact with .gitignore sparse-checkout: write using lockfile sparse-checkout: use in-process update for disable subcommand sparse-checkout: update working directory in-process sparse-checkout: sanitize for nested folders unpack-trees: add progress to clear_ce_flags() unpack-trees: hash less in cone mode sparse-checkout: init and set in cone mode sparse-checkout: use hashmaps for cone patterns sparse-checkout: add 'cone' mode trace2: add region in clear_ce_flags sparse-checkout: create 'disable' subcommand sparse-checkout: add '--stdin' option to set subcommand sparse-checkout: 'set' subcommand clone: add --sparse mode sparse-checkout: create 'init' subcommand ...
This commit is contained in:
108
unpack-trees.c
108
unpack-trees.c
@ -1269,7 +1269,8 @@ static int clear_ce_flags_1(struct index_state *istate,
|
||||
struct strbuf *prefix,
|
||||
int select_mask, int clear_mask,
|
||||
struct pattern_list *pl,
|
||||
enum pattern_match_result default_match);
|
||||
enum pattern_match_result default_match,
|
||||
int progress_nr);
|
||||
|
||||
/* Whole directory matching */
|
||||
static int clear_ce_flags_dir(struct index_state *istate,
|
||||
@ -1278,20 +1279,23 @@ static int clear_ce_flags_dir(struct index_state *istate,
|
||||
char *basename,
|
||||
int select_mask, int clear_mask,
|
||||
struct pattern_list *pl,
|
||||
enum pattern_match_result default_match)
|
||||
enum pattern_match_result default_match,
|
||||
int progress_nr)
|
||||
{
|
||||
struct cache_entry **cache_end;
|
||||
int dtype = DT_DIR;
|
||||
int rc;
|
||||
enum pattern_match_result ret;
|
||||
ret = path_matches_pattern_list(prefix->buf, prefix->len,
|
||||
basename, &dtype, pl, istate);
|
||||
enum pattern_match_result ret, orig_ret;
|
||||
orig_ret = path_matches_pattern_list(prefix->buf, prefix->len,
|
||||
basename, &dtype, pl, istate);
|
||||
|
||||
strbuf_addch(prefix, '/');
|
||||
|
||||
/* If undecided, use matching result of parent dir in defval */
|
||||
if (ret == UNDECIDED)
|
||||
if (orig_ret == UNDECIDED)
|
||||
ret = default_match;
|
||||
else
|
||||
ret = orig_ret;
|
||||
|
||||
for (cache_end = cache; cache_end != cache + nr; cache_end++) {
|
||||
struct cache_entry *ce = *cache_end;
|
||||
@ -1299,17 +1303,24 @@ static int clear_ce_flags_dir(struct index_state *istate,
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: check pl, if there are no patterns that may conflict
|
||||
* with ret (iow, we know in advance the incl/excl
|
||||
* decision for the entire directory), clear flag here without
|
||||
* calling clear_ce_flags_1(). That function will call
|
||||
* the expensive path_matches_pattern_list() on every entry.
|
||||
*/
|
||||
rc = clear_ce_flags_1(istate, cache, cache_end - cache,
|
||||
prefix,
|
||||
select_mask, clear_mask,
|
||||
pl, ret);
|
||||
if (pl->use_cone_patterns && orig_ret == MATCHED_RECURSIVE) {
|
||||
struct cache_entry **ce = cache;
|
||||
rc = (cache_end - cache) / sizeof(struct cache_entry *);
|
||||
|
||||
while (ce < cache_end) {
|
||||
(*ce)->ce_flags &= ~clear_mask;
|
||||
ce++;
|
||||
}
|
||||
} else if (pl->use_cone_patterns && orig_ret == NOT_MATCHED) {
|
||||
rc = (cache_end - cache) / sizeof(struct cache_entry *);
|
||||
} else {
|
||||
rc = clear_ce_flags_1(istate, cache, cache_end - cache,
|
||||
prefix,
|
||||
select_mask, clear_mask,
|
||||
pl, ret,
|
||||
progress_nr);
|
||||
}
|
||||
|
||||
strbuf_setlen(prefix, prefix->len - 1);
|
||||
return rc;
|
||||
}
|
||||
@ -1334,7 +1345,8 @@ static int clear_ce_flags_1(struct index_state *istate,
|
||||
struct strbuf *prefix,
|
||||
int select_mask, int clear_mask,
|
||||
struct pattern_list *pl,
|
||||
enum pattern_match_result default_match)
|
||||
enum pattern_match_result default_match,
|
||||
int progress_nr)
|
||||
{
|
||||
struct cache_entry **cache_end = cache + nr;
|
||||
|
||||
@ -1348,8 +1360,11 @@ static int clear_ce_flags_1(struct index_state *istate,
|
||||
int len, dtype;
|
||||
enum pattern_match_result ret;
|
||||
|
||||
display_progress(istate->progress, progress_nr);
|
||||
|
||||
if (select_mask && !(ce->ce_flags & select_mask)) {
|
||||
cache++;
|
||||
progress_nr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1370,20 +1385,26 @@ static int clear_ce_flags_1(struct index_state *istate,
|
||||
prefix,
|
||||
prefix->buf + prefix->len - len,
|
||||
select_mask, clear_mask,
|
||||
pl, default_match);
|
||||
pl, default_match,
|
||||
progress_nr);
|
||||
|
||||
/* clear_c_f_dir eats a whole dir already? */
|
||||
if (processed) {
|
||||
cache += processed;
|
||||
progress_nr += processed;
|
||||
strbuf_setlen(prefix, prefix->len - len);
|
||||
continue;
|
||||
}
|
||||
|
||||
strbuf_addch(prefix, '/');
|
||||
cache += clear_ce_flags_1(istate, cache, cache_end - cache,
|
||||
prefix,
|
||||
select_mask, clear_mask, pl,
|
||||
default_match);
|
||||
processed = clear_ce_flags_1(istate, cache, cache_end - cache,
|
||||
prefix,
|
||||
select_mask, clear_mask, pl,
|
||||
default_match, progress_nr);
|
||||
|
||||
cache += processed;
|
||||
progress_nr += processed;
|
||||
|
||||
strbuf_setlen(prefix, prefix->len - len - 1);
|
||||
continue;
|
||||
}
|
||||
@ -1398,24 +1419,41 @@ static int clear_ce_flags_1(struct index_state *istate,
|
||||
if (ret == MATCHED)
|
||||
ce->ce_flags &= ~clear_mask;
|
||||
cache++;
|
||||
progress_nr++;
|
||||
}
|
||||
|
||||
display_progress(istate->progress, progress_nr);
|
||||
return nr - (cache_end - cache);
|
||||
}
|
||||
|
||||
static int clear_ce_flags(struct index_state *istate,
|
||||
int select_mask, int clear_mask,
|
||||
struct pattern_list *pl)
|
||||
struct pattern_list *pl,
|
||||
int show_progress)
|
||||
{
|
||||
static struct strbuf prefix = STRBUF_INIT;
|
||||
char label[100];
|
||||
int rval;
|
||||
|
||||
strbuf_reset(&prefix);
|
||||
if (show_progress)
|
||||
istate->progress = start_delayed_progress(
|
||||
_("Updating index flags"),
|
||||
istate->cache_nr);
|
||||
|
||||
return clear_ce_flags_1(istate,
|
||||
xsnprintf(label, sizeof(label), "clear_ce_flags(0x%08lx,0x%08lx)",
|
||||
(unsigned long)select_mask, (unsigned long)clear_mask);
|
||||
trace2_region_enter("unpack_trees", label, the_repository);
|
||||
rval = clear_ce_flags_1(istate,
|
||||
istate->cache,
|
||||
istate->cache_nr,
|
||||
&prefix,
|
||||
select_mask, clear_mask,
|
||||
pl, 0);
|
||||
pl, 0, 0);
|
||||
trace2_region_leave("unpack_trees", label, the_repository);
|
||||
|
||||
stop_progress(&istate->progress);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1423,7 +1461,8 @@ static int clear_ce_flags(struct index_state *istate,
|
||||
*/
|
||||
static void mark_new_skip_worktree(struct pattern_list *pl,
|
||||
struct index_state *istate,
|
||||
int select_flag, int skip_wt_flag)
|
||||
int select_flag, int skip_wt_flag,
|
||||
int show_progress)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1447,7 +1486,7 @@ static void mark_new_skip_worktree(struct pattern_list *pl,
|
||||
* 2. Widen worktree according to sparse-checkout file.
|
||||
* Matched entries will have skip_wt_flag cleared (i.e. "in")
|
||||
*/
|
||||
clear_ce_flags(istate, select_flag, skip_wt_flag, pl);
|
||||
clear_ce_flags(istate, select_flag, skip_wt_flag, pl, show_progress);
|
||||
}
|
||||
|
||||
static int verify_absent(const struct cache_entry *,
|
||||
@ -1472,8 +1511,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
memset(&pl, 0, sizeof(pl));
|
||||
if (!core_apply_sparse_checkout || !o->update)
|
||||
o->skip_sparse_checkout = 1;
|
||||
if (!o->skip_sparse_checkout) {
|
||||
if (!o->skip_sparse_checkout && !o->pl) {
|
||||
char *sparse = git_pathdup("info/sparse-checkout");
|
||||
pl.use_cone_patterns = core_sparse_checkout_cone;
|
||||
if (add_patterns_from_file_to_list(sparse, "", 0, &pl, NULL) < 0)
|
||||
o->skip_sparse_checkout = 1;
|
||||
else
|
||||
@ -1511,7 +1551,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
|
||||
*/
|
||||
if (!o->skip_sparse_checkout)
|
||||
mark_new_skip_worktree(o->pl, o->src_index, 0, CE_NEW_SKIP_WORKTREE);
|
||||
mark_new_skip_worktree(o->pl, o->src_index, 0,
|
||||
CE_NEW_SKIP_WORKTREE, o->verbose_update);
|
||||
|
||||
if (!dfc)
|
||||
dfc = xcalloc(1, cache_entry_size(0));
|
||||
@ -1576,7 +1617,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
* If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
|
||||
* so apply_sparse_checkout() won't attempt to remove it from worktree
|
||||
*/
|
||||
mark_new_skip_worktree(o->pl, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
|
||||
mark_new_skip_worktree(o->pl, &o->result,
|
||||
CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE,
|
||||
o->verbose_update);
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; i < o->result.cache_nr; i++) {
|
||||
@ -1644,7 +1687,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
||||
|
||||
done:
|
||||
trace_performance_leave("unpack_trees");
|
||||
clear_pattern_list(&pl);
|
||||
if (!o->keep_pattern_list)
|
||||
clear_pattern_list(&pl);
|
||||
return ret;
|
||||
|
||||
return_failed:
|
||||
|
Reference in New Issue
Block a user