This patch teaches unpack_trees() to checkout/remove entries on working directories appropriately when sparse checkout area is changed. There are three kind of changes: - new_narrow_path: reset workdir to a completely new checkout area - add_narrow_path: keep current areas and add more entries - remove_narrow_path: remove some entries from current areas CE_WD_REMOVE is introduced to remove entries from working directories, but still keep them in index Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- cache.h | 3 ++ unpack-trees.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- unpack-trees.h | 4 +++ 3 files changed, 80 insertions(+), 1 deletions(-) diff --git a/cache.h b/cache.h index 6e875d5..f4025b5 100644 --- a/cache.h +++ b/cache.h @@ -167,6 +167,9 @@ struct cache_entry { #define CE_HASHED (0x100000) #define CE_UNHASHED (0x200000) +/* Only remove in work directory, not index */ +#define CE_WD_REMOVE (0x400000) + /* * Extended on-disk flags */ diff --git a/unpack-trees.c b/unpack-trees.c index ce4c826..10f377c 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -96,7 +96,7 @@ static int check_updates(struct unpack_trees_options *o) if (o->update && o->verbose_update) { for (total = cnt = 0; cnt < index->cache_nr; cnt++) { struct cache_entry *ce = index->cache[cnt]; - if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) + if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WD_REMOVE)) total++; } @@ -108,6 +108,13 @@ static int check_updates(struct unpack_trees_options *o) for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; + if (ce->ce_flags & CE_WD_REMOVE) { + display_progress(progress, ++cnt); + if (o->update) + unlink_entry(ce); + continue; + } + if (ce->ce_flags & CE_REMOVE) { display_progress(progress, ++cnt); if (o->update) @@ -133,6 +140,66 @@ static int check_updates(struct unpack_trees_options *o) return errs != 0; } +static int verify_uptodate(struct cache_entry *ce, struct unpack_trees_options *o); +static int apply_narrow_spec(struct unpack_trees_options *o) +{ + struct index_state *index = &o->result; + int i; + + if (!(o->new_narrow_path | o->add_narrow_path | o->remove_narrow_path)) + return 0; + + for (i = 0; i < index->cache_nr; i++) { + struct cache_entry *ce = index->cache[i]; + int was_checkout = ce_checkout(ce); + int match = match_narrow_spec(o->narrow_spec, ce->name); + + if (ce_stage(ce)) + continue; + + if (o->new_narrow_path) { + if (match) + ce_mark_checkout(ce); + else + ce_mark_no_checkout(ce); + } + + if (o->add_narrow_path && match) + ce_mark_checkout(ce); + + if (o->remove_narrow_path && match) + ce_mark_no_checkout(ce); + + /* Update worktree, add/remove entries if needed */ + + /* + * We only care about files getting into the checkout area + * If merge strategies want to remove some, go ahead + */ + if (ce->ce_flags & CE_REMOVE) + continue; + + if (was_checkout && ce_no_checkout(ce)) { + /* + * If CE_UPDATE is set, verify_uptodate() must be called already + * also stat info may have lost after merged_entry() so calling + * verify_uptodate() again may fail + */ + if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate(ce, o)) + return -1; + ce->ce_flags |= CE_WD_REMOVE; + } + if (!was_checkout && ce_checkout(ce)) + ce->ce_flags |= CE_UPDATE; + + /* merge strategies may set CE_UPDATE outside checkout area */ + if (ce_no_checkout(ce)) + ce->ce_flags &= ~CE_UPDATE; + + } + return 0; +} + static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o) { int ret = o->fn(src, o); @@ -409,6 +476,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options if (o->trivial_merges_only && o->nontrivial_merge) return unpack_failed(o, "Merge requires file-level merging"); + if (apply_narrow_spec(o)) + return unpack_failed(o, NULL); + o->src_index = NULL; ret = check_updates(o) ? (-2) : 0; if (o->dst_index) @@ -677,6 +747,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, return -1; invalidate_ce_path(old, o); } + if (ce_no_checkout(old)) + update |= CE_NO_CHECKOUT; } else { if (verify_absent(merge, "overwritten", o)) diff --git a/unpack-trees.h b/unpack-trees.h index 6b1971f..0d899b6 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -43,6 +43,9 @@ struct unpack_trees_options { aggressive:1, skip_unmerged:1, initial_checkout:1, + new_narrow_path:1, + add_narrow_path:2, + remove_narrow_path:2, gently:1; const char *prefix; int pos; @@ -54,6 +57,7 @@ struct unpack_trees_options { int merge_size; struct cache_entry *df_conflict_entry; + struct narrow_spec *narrow_spec; void *unpack_data; struct index_state *dst_index; -- 1.6.0.96.g2fad1.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html