When unpack_trees() nearly completes, sparse pattern is applied and will prevent any updates (CE_UPDATE, CE_WT_REMOVE, CE_REMOVE) outside sparse checkout area by clearing these flags. Unfortunately CE_REMOVE also instructs write_index() to remove files from the index. By clearing this flag, index may keep unwanted files. This patch turns CE_REMOVE in unpack-trees.c to CE_REMOVE|CE_WT_REMOVE and only remove files from worktree if CE_WT_REMOVE is set. CE_REMOVE is now only meaningful to index operations and CE_WT_REMOVE to worktree ones. This fault made the test suite itself faulty. With this fault fixed, two other faults are revealed :( Reported in http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=583699 Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- cache.h | 3 +-- t/t1011-read-tree-sparse-checkout.sh | 9 ++++++++- unpack-trees.c | 22 ++++++++++++---------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/cache.h b/cache.h index 0d101e4..4e7bb62 100644 --- a/cache.h +++ b/cache.h @@ -179,8 +179,7 @@ struct cache_entry { #define CE_UNHASHED (0x200000) #define CE_CONFLICTED (0x800000) -/* Only remove in work directory, not index */ -#define CE_WT_REMOVE (0x400000) +#define CE_WT_REMOVE (0x400000) /* remove in work directory */ #define CE_UNPACKED (0x1000000) diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 62246db..885578a 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -138,7 +138,7 @@ test_expect_success 'read-tree adds to worktree, absent case' ' test ! -f sub/added ' -test_expect_success 'read-tree adds to worktree, dirty case' ' +test_expect_failure 'read-tree adds to worktree, dirty case' ' echo init.t > .git/info/sparse-checkout && git checkout -f removed && mkdir sub && @@ -147,4 +147,11 @@ test_expect_success 'read-tree adds to worktree, dirty case' ' grep -q dirty sub/added ' +test_expect_success 'read-tree --reset removes outside worktree' ' + echo init.t > .git/info/sparse-checkout && + git checkout -f top && + git reset --hard removed && + test -z "$(git ls-files sub/added)" +' + test_done diff --git a/unpack-trees.c b/unpack-trees.c index e8f03f5..f2d148c 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -53,6 +53,9 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce, clear |= CE_HASHED | CE_UNHASHED; + if (set & CE_REMOVE) + set |= CE_WT_REMOVE; + memcpy(new, ce, size); new->next = NULL; new->ce_flags = (new->ce_flags & ~clear) | set; @@ -84,7 +87,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 | CE_WT_REMOVE)) + if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE)) total++; } @@ -104,12 +107,6 @@ static int check_updates(struct unpack_trees_options *o) unlink_entry(ce); continue; } - - if (ce->ce_flags & CE_REMOVE) { - display_progress(progress, ++cnt); - if (o->update) - unlink_entry(ce); - } } remove_marked_cache_entries(&o->result); remove_scheduled_dirs(); @@ -799,10 +796,15 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options /* * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout * area as a result of ce_skip_worktree() shortcuts in - * verify_absent() and verify_uptodate(). Clear them. + * verify_absent() and verify_uptodate(). + * Make sure they don't modify worktree. */ - if (ce_skip_worktree(ce)) - ce->ce_flags &= ~(CE_UPDATE | CE_REMOVE); + if (ce_skip_worktree(ce)) { + ce->ce_flags &= ~CE_UPDATE; + + if (ce->ce_flags & CE_REMOVE) + ce->ce_flags &= ~CE_WT_REMOVE; + } else empty_worktree = 0; -- 1.7.1.rc1.69.g24c2f7 -- 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