[PATCH 11/14] unpack_trees(): add support for sparse checkout
From: Nguyễn Thái Ngọc Duy <hidden>
Date: 2016-06-15 22:45:23
Subsystem:
the rest · Maintainer:
Linus Torvalds
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 <redacted> --- 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