This patch teaches unpack_trees() to checkout/remove entries on working directories appropriately when narrow area is changed. There are three kind of changes: - new_narrow_path: reset workdir to a new narrow checkout - add_narrow_path: keep current narrow areas and add more entries - remove_narrow_path: remove some entries from current narrow areas A simple "narrow spec" is introduced to specify what entries is in narrow area. For now it is just a list of prefix separated by colon. 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 | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unpack-trees.h | 6 +++ 3 files changed, 109 insertions(+), 0 deletions(-) diff --git a/cache.h b/cache.h index 2b2c90f..1fc0f83 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 e59d144..968cc98 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -96,6 +96,15 @@ 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_WD_REMOVE) { + total++; + continue; + } + + if (ce_no_checkout(ce)) + continue; + if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) total++; } @@ -108,6 +117,16 @@ 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_no_checkout(ce)) + continue; + if (ce->ce_flags & CE_REMOVE) { display_progress(progress, ++cnt); if (o->update) @@ -121,6 +140,9 @@ 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_no_checkout(ce)) + continue; + if (ce->ce_flags & CE_UPDATE) { display_progress(progress, ++cnt); ce->ce_flags &= ~CE_UPDATE; @@ -133,6 +155,47 @@ 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_checkout(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, o->narrow_prefix); + + 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); + + if (was_checkout && ce_no_checkout(ce)) { + if (verify_uptodate(ce, o)) + return -1; + ce->ce_flags |= CE_WD_REMOVE; + } + if (!was_checkout && ce_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 +472,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_checkout(o)) + return unpack_failed(o, NULL); + o->src_index = NULL; ret = check_updates(o) ? (-2) : 0; if (o->dst_index) @@ -677,6 +743,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)) @@ -726,6 +794,38 @@ static void show_stage_entry(FILE *o, } #endif +int match_narrow_spec(const char *spec_, const char *path, const char *prefix) +{ + int match = 0; + char *spec, *cur_spec; + int prefix_len = 0; + + if (!spec_) + return 1; /* always match if spec_ is NULL */ + if (prefix) { + if (prefixcmp(path, prefix)) + return 0; + prefix_len = strlen(prefix); + } + + spec = cur_spec = xstrdup(spec_); + + while (!match) { + char *next_spec = strchr(cur_spec, ':'); + if (next_spec) + *next_spec = '\0'; + + if (!fnmatch(cur_spec, path+prefix_len, 0)) + match = 1; + + if (!next_spec) + break; + cur_spec = next_spec+1; + } + free(spec); + return match; +} + int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o) { struct cache_entry *index; diff --git a/unpack-trees.h b/unpack-trees.h index 0d26f3d..942a007 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -27,6 +27,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; @@ -38,6 +41,8 @@ struct unpack_trees_options { int merge_size; struct cache_entry *df_conflict_entry; + const char *narrow_spec; + const char *narrow_prefix; void *unpack_data; struct index_state *dst_index; @@ -48,6 +53,7 @@ struct unpack_trees_options { extern int unpack_trees(unsigned n, struct tree_desc *t, struct unpack_trees_options *options); +int match_narrow_spec(const char *spec_, const char *path, const char *prefix); int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o); int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o); int bind_merge(struct cache_entry **src, struct unpack_trees_options *o); -- 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