* [PATCH 1/3] Fix sparse checkout not removing files from index
@ 2010-07-26 9:08 Nguyễn Thái Ngọc Duy
2010-07-26 9:08 ` [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() Nguyễn Thái Ngọc Duy
` (2 more replies)
0 siblings, 3 replies; 17+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2010-07-26 9:08 UTC (permalink / raw)
To: git, Junio C Hamano; +Cc: Nguyễn Thái Ngọc Duy
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@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() 2010-07-26 9:08 [PATCH 1/3] Fix sparse checkout not removing files from index Nguyễn Thái Ngọc Duy @ 2010-07-26 9:08 ` Nguyễn Thái Ngọc Duy 2010-07-31 2:11 ` Jonathan Nieder 2010-07-26 9:08 ` [PATCH 3/3] Mark new entries skip-worktree appropriately Nguyễn Thái Ngọc Duy 2010-07-30 1:35 ` [PATCH 1/3] Fix sparse checkout not removing files from index Jonathan Nieder 2 siblings, 1 reply; 17+ messages in thread From: Nguyễn Thái Ngọc Duy @ 2010-07-26 9:08 UTC (permalink / raw) To: git, Junio C Hamano; +Cc: Nguyễn Thái Ngọc Duy The idea of sparse checkout is conflicted entries should always stay in worktree, regardless $GIT_DIR/info/sparse-checkout. Therefore, ce_stage(ce) usually means no CE_SKIP_WORKTREE. This is true when all entries have been merged into the index, and identical staged entries collapsed. However, will_have_skip_worktree() since f1f523e (unpack-trees(): ignore worktree check outside checkout area) is also used earlier in verify_* functions, when entries have not been merged to index yet and ce_stage() may not be zero. Checking ce_stage() then can make unnecessary verification on entries outside checkout area and error out. This fixes part of test case "read-tree adds to worktree, dirty case". The error is changed from error: Untracked working tree file 'sub/added' would be overwritten by merge. before this patch to grep: sub/added: No such file or directory which will be addressed in the next patch. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> --- unpack-trees.c | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/unpack-trees.c b/unpack-trees.c index f2d148c..7ea8c5f 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -135,9 +135,6 @@ static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_t { const char *basename; - if (ce_stage(ce)) - return 0; - basename = strrchr(ce->name, '/'); basename = basename ? basename+1 : ce->name; return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0; @@ -147,7 +144,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt { int was_skip_worktree = ce_skip_worktree(ce); - if (will_have_skip_worktree(ce, o)) + if (!ce_stage(ce) && will_have_skip_worktree(ce, o)) ce->ce_flags |= CE_SKIP_WORKTREE; else ce->ce_flags &= ~CE_SKIP_WORKTREE; -- 1.7.1.rc1.69.g24c2f7 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() 2010-07-26 9:08 ` [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() Nguyễn Thái Ngọc Duy @ 2010-07-31 2:11 ` Jonathan Nieder 2010-07-31 3:12 ` Nguyen Thai Ngoc Duy 0 siblings, 1 reply; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 2:11 UTC (permalink / raw) To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano Nguyễn Thái Ngọc Duy wrote: > The idea of sparse checkout is conflicted entries should always stay > in worktree, regardless $GIT_DIR/info/sparse-checkout. Therefore, > ce_stage(ce) usually means no CE_SKIP_WORKTREE. This is true when all > entries have been merged into the index, and identical staged entries > collapsed. > > However, will_have_skip_worktree() since f1f523e (unpack-trees(): > ignore worktree check outside checkout area) is also used earlier in > verify_* functions, when entries have not been merged to index yet > and ce_stage() may not be zero. Checking ce_stage() then can make > unnecessary verification on entries outside checkout area and error out. s/make/provoke/? So: conflicts from unmerged index entries are supposed to be kept in the work tree; but unpack_trees() is checking too early and seeing conflicts where there are none. Do I understand correctly? > This fixes part of test case "read-tree adds to worktree, dirty case". A summary might help people who do not remember the test: So attempting to add a file outside the checkout area where there is a file already present (as in t1011.13 "read-tree adds to worktree, dirty case") will no longer error out with error: Untracked working tree file 'sub/added' would be overwritten by merge. but instead will remove the file. (The latter problem will be addressed in a later patch.) > +++ a/unpack-trees.c > +++ b/unpack-trees.c > @@ -135,9 +135,6 @@ static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_t > { > const char *basename; > > - if (ce_stage(ce)) > - return 0; > - > basename = strrchr(ce->name, '/'); > basename = basename ? basename+1 : ce->name; > return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0; > @@ -147,7 +144,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt > { > int was_skip_worktree = ce_skip_worktree(ce); > > - if (will_have_skip_worktree(ce, o)) > + if (!ce_stage(ce) && will_have_skip_worktree(ce, o)) > ce->ce_flags |= CE_SKIP_WORKTREE; > else > ce->ce_flags &= ~CE_SKIP_WORKTREE; Makes sense. Thanks, Jonathan ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() 2010-07-31 2:11 ` Jonathan Nieder @ 2010-07-31 3:12 ` Nguyen Thai Ngoc Duy 0 siblings, 0 replies; 17+ messages in thread From: Nguyen Thai Ngoc Duy @ 2010-07-31 3:12 UTC (permalink / raw) To: Jonathan Nieder; +Cc: git, Junio C Hamano 2010/7/31 Jonathan Nieder <jrnieder@gmail.com>: > Nguyễn Thái Ngọc Duy wrote: > >> The idea of sparse checkout is conflicted entries should always stay >> in worktree, regardless $GIT_DIR/info/sparse-checkout. Therefore, >> ce_stage(ce) usually means no CE_SKIP_WORKTREE. This is true when all >> entries have been merged into the index, and identical staged entries >> collapsed. >> >> However, will_have_skip_worktree() since f1f523e (unpack-trees(): >> ignore worktree check outside checkout area) is also used earlier in >> verify_* functions, when entries have not been merged to index yet >> and ce_stage() may not be zero. Checking ce_stage() then can make >> unnecessary verification on entries outside checkout area and error out. > > s/make/provoke/? > > So: conflicts from unmerged index entries are supposed to be kept in > the work tree; but unpack_trees() is checking too early and seeing > conflicts where there are none. Do I understand correctly? Correct. -- Duy ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/3] Mark new entries skip-worktree appropriately 2010-07-26 9:08 [PATCH 1/3] Fix sparse checkout not removing files from index Nguyễn Thái Ngọc Duy 2010-07-26 9:08 ` [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() Nguyễn Thái Ngọc Duy @ 2010-07-26 9:08 ` Nguyễn Thái Ngọc Duy 2010-07-31 2:32 ` Jonathan Nieder 2010-07-30 1:35 ` [PATCH 1/3] Fix sparse checkout not removing files from index Jonathan Nieder 2 siblings, 1 reply; 17+ messages in thread From: Nguyễn Thái Ngọc Duy @ 2010-07-26 9:08 UTC (permalink / raw) To: git, Junio C Hamano; +Cc: Nguyễn Thái Ngọc Duy Sparse checkout updates worktree based on the old and new skip-worktree status when $GIT_DIR/info/sparse-checkout changes: old = ce_skip_worktree(ce); // current skip-worktree new = will_have_skip_work_tree(ce); // from $GIT..sparse-checkout if (old && !new) add_file_back(ce); // shrink checkout area if (!old && new) remove_file_out(ce); [1] // enlarge checkout area New entries after merging will always have skip-worktree unset (i.e. old = 0). If those files are filtered out by $GIT_DIR/info/sparse-checkout (i.e. new != 0), then case [1] will happen. But there is nothing to remove because they're new. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> --- t/t1011-read-tree-sparse-checkout.sh | 2 +- unpack-trees.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 885578a..86a6246 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_failure 'read-tree adds to worktree, dirty case' ' +test_expect_success 'read-tree adds to worktree, dirty case' ' echo init.t > .git/info/sparse-checkout && git checkout -f removed && mkdir sub && diff --git a/unpack-trees.c b/unpack-trees.c index 7ea8c5f..f98b1cb 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1091,6 +1091,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, if (!old) { if (verify_absent(merge, "overwritten", o)) return -1; + if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o)) + update |= CE_SKIP_WORKTREE; invalidate_ce_path(merge, o); } else if (!(old->ce_flags & CE_CONFLICTED)) { /* -- 1.7.1.rc1.69.g24c2f7 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 3/3] Mark new entries skip-worktree appropriately 2010-07-26 9:08 ` [PATCH 3/3] Mark new entries skip-worktree appropriately Nguyễn Thái Ngọc Duy @ 2010-07-31 2:32 ` Jonathan Nieder 2010-07-31 3:13 ` Nguyen Thai Ngoc Duy 0 siblings, 1 reply; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 2:32 UTC (permalink / raw) To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano Nguyễn Thái Ngọc Duy wrote: > Sparse checkout updates worktree based on the old and new > skip-worktree status when $GIT_DIR/info/sparse-checkout changes: > > old = ce_skip_worktree(ce); // current skip-worktree > new = will_have_skip_work_tree(ce); // from $GIT..sparse-checkout > if (old && !new) add_file_back(ce); // shrink checkout area > if (!old && new) remove_file_out(ce); [1] // enlarge checkout area > > New entries after merging will always have skip-worktree unset > (i.e. old = 0). If those files are filtered out by > $GIT_DIR/info/sparse-checkout (i.e. new != 0), then case [1] will > happen. But there is nothing to remove because they're new. When using unpack_trees to add a new file, there is no in-file index entry to grab the previous skip worktree bit from. If it is outside the checkout area, we should pretend it was skipped before, too; otherwise a checkout can cause a file on disk whose name coincides with a newly added outside-worktree file to be deleted. Do I understand correctly? > +++ b/unpack-trees.c > @@ -1091,6 +1091,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, > if (!old) { > if (verify_absent(merge, "overwritten", o)) > return -1; > + if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o)) > + update |= CE_SKIP_WORKTREE; > invalidate_ce_path(merge, o); > } else if (!(old->ce_flags & CE_CONFLICTED)) { > /* Looks sane. Thanks for the fixes, Jonathan ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/3] Mark new entries skip-worktree appropriately 2010-07-31 2:32 ` Jonathan Nieder @ 2010-07-31 3:13 ` Nguyen Thai Ngoc Duy 2010-07-31 3:29 ` Jonathan Nieder 0 siblings, 1 reply; 17+ messages in thread From: Nguyen Thai Ngoc Duy @ 2010-07-31 3:13 UTC (permalink / raw) To: Jonathan Nieder; +Cc: git, Junio C Hamano 2010/7/31 Jonathan Nieder <jrnieder@gmail.com>: > Nguyễn Thái Ngọc Duy wrote: > >> Sparse checkout updates worktree based on the old and new >> skip-worktree status when $GIT_DIR/info/sparse-checkout changes: >> >> old = ce_skip_worktree(ce); // current skip-worktree >> new = will_have_skip_work_tree(ce); // from $GIT..sparse-checkout >> if (old && !new) add_file_back(ce); // shrink checkout area >> if (!old && new) remove_file_out(ce); [1] // enlarge checkout area >> >> New entries after merging will always have skip-worktree unset >> (i.e. old = 0). If those files are filtered out by >> $GIT_DIR/info/sparse-checkout (i.e. new != 0), then case [1] will >> happen. But there is nothing to remove because they're new. > > When using unpack_trees to add a new file, there is no in-file > index entry to grab the previous skip worktree bit from. If it > is outside the checkout area, we should pretend it was skipped before, > too; otherwise a checkout can cause a file on disk whose name > coincides with a newly added outside-worktree file to be deleted. > > Do I understand correctly? Yes. -- Duy ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/3] Mark new entries skip-worktree appropriately 2010-07-31 3:13 ` Nguyen Thai Ngoc Duy @ 2010-07-31 3:29 ` Jonathan Nieder 0 siblings, 0 replies; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 3:29 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano Nguyen Thai Ngoc Duy wrote: > 2010/7/31 Jonathan Nieder <jrnieder@gmail.com>: >> Do I understand correctly? > > Yes. Ah, good. This is fun code to play with. Thanks for putting it together. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-26 9:08 [PATCH 1/3] Fix sparse checkout not removing files from index Nguyễn Thái Ngọc Duy 2010-07-26 9:08 ` [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() Nguyễn Thái Ngọc Duy 2010-07-26 9:08 ` [PATCH 3/3] Mark new entries skip-worktree appropriately Nguyễn Thái Ngọc Duy @ 2010-07-30 1:35 ` Jonathan Nieder 2010-07-30 8:24 ` Nguyen Thai Ngoc Duy 2 siblings, 1 reply; 17+ messages in thread From: Jonathan Nieder @ 2010-07-30 1:35 UTC (permalink / raw) To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano Nguyễn Thái Ngọc Duy wrote: > Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> The log message left me confused. Let’s see if the code is easier. > +++ 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 */ Before[1], CE_REMOVE was used by read-tree et al in core to represent something to be removed from the index file and work tree (e.g., when switching branches). In the new order, one uses CE_REMOVE|CE_WT_REMOVE for that, right? > +++ b/t/t1011-read-tree-sparse-checkout.sh > @@ -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)" > +' > + Using reset --hard to remove a file outside the sparse checkout. A sane, simple test; thanks. (Nitpick: I would have used >empty && git ls-files sub/added >output && test_cmp empty output even though that does not produce any more helpful output in this case.) > +++ 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; > + A bridge between the old and new worlds. I would have added CE_WT_REMOVE to callers instead (they all pass constants more or less), but I suppose this way makes the patch shorter. [...] > @@ -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)) Only entries marked CE_WT_REMOVE will be touched by read-tree -u. > @@ -104,12 +107,6 @@ static int check_updates(struct unpack_trees_options *o) > unlink_entry(ce); > continue; > } > - > - if (ce->ce_flags & CE_REMOVE) { [...] and the CE_WT_REMOVE case takes care of that. Makes sense. > @@ -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; Ah, and at last we come to the fix. :) This is a little tricky: the CE_WT_REMOVE case (without CE_REMOVE) represents a narrowing of the checkout and should be preserved, while CE_WT_REMOVE|CE_REMOVE represents a removed index entry and should be changed to just CE_REMOVE. But it is a clear improvement over the code from before and should behave as advertised now. So aside from the log message, Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Thanks. [1] v1.6.6.1~23^2~1 (Make on-disk index representation separate from in-core one, 2008-01-14) and v0.99~295 (git-read-tree: remove deleted files in the working directory, 2005-06-09). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-30 1:35 ` [PATCH 1/3] Fix sparse checkout not removing files from index Jonathan Nieder @ 2010-07-30 8:24 ` Nguyen Thai Ngoc Duy 2010-07-30 19:50 ` Jonathan Nieder 0 siblings, 1 reply; 17+ messages in thread From: Nguyen Thai Ngoc Duy @ 2010-07-30 8:24 UTC (permalink / raw) To: Jonathan Nieder; +Cc: git, Junio C Hamano 2010/7/30 Jonathan Nieder <jrnieder@gmail.com>: >> +++ 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 */ > > Before[1], CE_REMOVE was used by read-tree et al in core to represent > something to be removed from the index file and work tree (e.g., when > switching branches). > > In the new order, one uses CE_REMOVE|CE_WT_REMOVE for that, right? For unpack_trees() only, yes. You made me grep for CE_REMOVE and found that do_diff_cache() may turn CE_REMOVE on. The function is used by blame and reset. Hmm.. It's for removing staged entries. So it's probably fine. >> +++ b/t/t1011-read-tree-sparse-checkout.sh >> @@ -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)" >> +' >> + > > Using reset --hard to remove a file outside the sparse checkout. > A sane, simple test; thanks. (Nitpick: I would have used > > >empty && > git ls-files sub/added >output && > test_cmp empty output > > even though that does not produce any more helpful output in this > case.) Thanks. That looks better. > >> +++ 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; >> + > > A bridge between the old and new worlds. > > I would have added CE_WT_REMOVE to callers instead (they all pass > constants more or less), but I suppose this way makes the patch > shorter. It'd better be done in one place. I don't expect anybody to set CE_REMOVE without CE_WT_REMOVE any time soon. Adding it the the callers, the new callers might miss it. >> @@ -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; > > Ah, and at last we come to the fix. :) > > This is a little tricky: the CE_WT_REMOVE case (without CE_REMOVE) > represents a narrowing of the checkout and should be preserved, > while CE_WT_REMOVE|CE_REMOVE represents a removed index entry and > should be changed to just CE_REMOVE. Yeah. I did wonder if it's worth a comment to explain. I forget why I did not add that comment now. -- Duy ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-30 8:24 ` Nguyen Thai Ngoc Duy @ 2010-07-30 19:50 ` Jonathan Nieder 2010-07-31 1:04 ` Jonathan Nieder 0 siblings, 1 reply; 17+ messages in thread From: Jonathan Nieder @ 2010-07-30 19:50 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano Nguyen Thai Ngoc Duy wrote: > For unpack_trees() only, yes. Ah, that is what I was missing. So would the following be correct? Subject: unpack-trees: let read-tree -u remove index entries outside sparse area To avoid touching the worktree outside a sparse checkout, when the update flag is enabled unpack_trees() clears the CE_UPDATE and CE_REMOVE flags on entries that do not match the sparse pattern before actually committing any updates to the index file or worktree. The effect on the index was unintentional; sparse checkout was never meant to prevent index updates outside the area checked out. And the result is very confusing: for example, after a failed merge, currently "git reset --hard" does not reset the state completely but an additional "git reset --mixed" will. So stop clearing the CE_REMOVE flag. Instead, maintain a CE_WT_REMOVE flag to separately track whether a particular file removal should apply to the worktree in addition to the index or not. The CE_WT_REMOVE flag is used already to mark files that should be removed because of a narrowing checkout area. That usage will still apply; do not clear the CE_WT_REMOVE flag in that case (detectable because the CE_REMOVE flag is not set). This bug masked some other bugs illustrated by the test suite, which will be addressed by later patches. Reported-by: Frédéric Brière <fbriere@fbriere.net> Fixes: http://bugs.debian.org/583699 > It'd better be done in one place. I think I understand better now, and now I agree. (This patch is not a change in the semantics of CE_REMOVE, but just some new unpack-trees bookkeeping.) > 2010/7/30 Jonathan Nieder <jrnieder@gmail.com>: >> This is a little tricky: the CE_WT_REMOVE case (without CE_REMOVE) >> represents a narrowing of the checkout and should be preserved, >> while CE_WT_REMOVE|CE_REMOVE represents a removed index entry and >> should be changed to just CE_REMOVE. > > Yeah. I did wonder if it's worth a comment to explain. I forget why I > did not add that comment now. What happens if an index entry is removed at the same time as the checkout is narrowed? ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-30 19:50 ` Jonathan Nieder @ 2010-07-31 1:04 ` Jonathan Nieder 2010-07-31 1:05 ` [PATCH 1/2] t1011 (sparse checkout): style nitpicks Jonathan Nieder ` (2 more replies) 0 siblings, 3 replies; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 1:04 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano Jonathan Nieder wrote: > What happens if an index entry is removed at the same time as the > checkout is narrowed? Hm, maybe something like this would help. Jonathan Nieder (2): t1011 (sparse checkout): style nitpicks read-tree -m -u: always remove relevant files when narrowing checkout cache.h | 3 +- t/t1011-read-tree-sparse-checkout.sh | 129 +++++++++++++++++++++------------- unpack-trees.c | 42 +++-------- 3 files changed, 94 insertions(+), 80 deletions(-) ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/2] t1011 (sparse checkout): style nitpicks 2010-07-31 1:04 ` Jonathan Nieder @ 2010-07-31 1:05 ` Jonathan Nieder 2010-07-31 1:09 ` [PATCH 2/2] read-tree -m -u: always remove relevant files when narrowing checkout Jonathan Nieder 2010-07-31 3:28 ` [PATCH 1/3] Fix sparse checkout not removing files from index Nguyen Thai Ngoc Duy 2 siblings, 0 replies; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 1:05 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano The exit status of "git ls-files" in test -z "$(git ls-files sub/added)" is ignored. So redirect output to a file and compare to an empty file with test_cmp instead. While changing that, tweak the rest of the script to more closely follow the test style guide. Guarding setup commands with test_expect_success makes it easy to see the scope in which some particular data is used; removal of whitespace after >redirection operators is just for consistency. Cc: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> --- t/t1011-read-tree-sparse-checkout.sh | 108 ++++++++++++++++++--------------- 1 files changed, 59 insertions(+), 49 deletions(-) diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 885578a..2955071 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -1,16 +1,30 @@ #!/bin/sh -test_description='sparse checkout tests' +test_description='sparse checkout tests + +* (tag: removed, master) removed +| D sub/added +* (HEAD, tag: top) modified and added +| M init.t +| A sub/added +* (tag: init) init + A init.t +' . ./test-lib.sh -cat >expected <<EOF -100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added -EOF test_expect_success 'setup' ' + cat >expected <<-\EOF && + 100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t + 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added + EOF + cat >expected.swt <<-\EOF && + H init.t + H sub/added + EOF + test_commit init && - echo modified >> init.t && + echo modified >>init.t && mkdir sub && touch sub/added && git add init.t sub/added && @@ -20,26 +34,22 @@ test_expect_success 'setup' ' git commit -m removed && git tag removed && git checkout top && - git ls-files --stage > result && + git ls-files --stage >result && test_cmp expected result ' -cat >expected.swt <<EOF -H init.t -H sub/added -EOF test_expect_success 'read-tree without .git/info/sparse-checkout' ' git read-tree -m -u HEAD && - git ls-files --stage > result && + git ls-files --stage >result && test_cmp expected result && - git ls-files -t > result && + git ls-files -t >result && test_cmp expected.swt result ' test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' ' - echo > .git/info/sparse-checkout + echo >.git/info/sparse-checkout git read-tree -m -u HEAD && - git ls-files -t > result && + git ls-files -t >result && test_cmp expected.swt result && test -f init.t && test -f sub/added @@ -47,9 +57,9 @@ test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' ' test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-checkout and enabled' ' git config core.sparsecheckout true && - echo > .git/info/sparse-checkout && + echo >.git/info/sparse-checkout && git read-tree --no-sparse-checkout -m -u HEAD && - git ls-files -t > result && + git ls-files -t >result && test_cmp expected.swt result && test -f init.t && test -f sub/added @@ -57,101 +67,101 @@ test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse- test_expect_success 'read-tree with empty .git/info/sparse-checkout' ' git config core.sparsecheckout true && - echo > .git/info/sparse-checkout && + echo >.git/info/sparse-checkout && test_must_fail git read-tree -m -u HEAD && - git ls-files --stage > result && + git ls-files --stage >result && test_cmp expected result && - git ls-files -t > result && + git ls-files -t >result && test_cmp expected.swt result && test -f init.t && test -f sub/added ' -cat >expected.swt <<EOF -S init.t -H sub/added -EOF test_expect_success 'match directories with trailing slash' ' + cat >expected.swt-noinit <<-\EOF && + S init.t + H sub/added + EOF + echo sub/ > .git/info/sparse-checkout && git read-tree -m -u HEAD && git ls-files -t > result && - test_cmp expected.swt result && + test_cmp expected.swt-noinit result && test ! -f init.t && test -f sub/added ' -cat >expected.swt <<EOF -H init.t -H sub/added -EOF test_expect_failure 'match directories without trailing slash' ' - echo init.t > .git/info/sparse-checkout && - echo sub >> .git/info/sparse-checkout && + echo init.t >.git/info/sparse-checkout && + echo sub >>.git/info/sparse-checkout && git read-tree -m -u HEAD && - git ls-files -t > result && + git ls-files -t >result && test_cmp expected.swt result && test ! -f init.t && test -f sub/added ' -cat >expected.swt <<EOF -H init.t -S sub/added -EOF test_expect_success 'checkout area changes' ' - echo init.t > .git/info/sparse-checkout && + cat >expected.swt-nosub <<-\EOF && + H init.t + S sub/added + EOF + + echo init.t >.git/info/sparse-checkout && git read-tree -m -u HEAD && - git ls-files -t > result && - test_cmp expected.swt result && + git ls-files -t >result && + test_cmp expected.swt-nosub result && test -f init.t && test ! -f sub/added ' test_expect_success 'read-tree updates worktree, absent case' ' - echo sub/added > .git/info/sparse-checkout && + echo sub/added >.git/info/sparse-checkout && git checkout -f top && git read-tree -m -u HEAD^ && test ! -f init.t ' test_expect_success 'read-tree updates worktree, dirty case' ' - echo sub/added > .git/info/sparse-checkout && + echo sub/added >.git/info/sparse-checkout && git checkout -f top && - echo dirty > init.t && + echo dirty >init.t && git read-tree -m -u HEAD^ && grep -q dirty init.t && rm init.t ' test_expect_success 'read-tree removes worktree, dirty case' ' - echo init.t > .git/info/sparse-checkout && + echo init.t >.git/info/sparse-checkout && git checkout -f top && - echo dirty > added && + echo dirty >added && git read-tree -m -u HEAD^ && grep -q dirty added ' test_expect_success 'read-tree adds to worktree, absent case' ' - echo init.t > .git/info/sparse-checkout && + echo init.t >.git/info/sparse-checkout && git checkout -f removed && git read-tree -u -m HEAD^ && test ! -f sub/added ' test_expect_failure 'read-tree adds to worktree, dirty case' ' - echo init.t > .git/info/sparse-checkout && + echo init.t >.git/info/sparse-checkout && git checkout -f removed && mkdir sub && - echo dirty > sub/added && + echo dirty >sub/added && git read-tree -u -m HEAD^ && grep -q dirty sub/added ' test_expect_success 'read-tree --reset removes outside worktree' ' - echo init.t > .git/info/sparse-checkout && + >empty && + echo init.t >.git/info/sparse-checkout && git checkout -f top && git reset --hard removed && - test -z "$(git ls-files sub/added)" + git ls-files sub/added >result && + test_cmp empty result ' test_done -- 1.7.2.1.544.ga752d.dirty ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/2] read-tree -m -u: always remove relevant files when narrowing checkout 2010-07-31 1:04 ` Jonathan Nieder 2010-07-31 1:05 ` [PATCH 1/2] t1011 (sparse checkout): style nitpicks Jonathan Nieder @ 2010-07-31 1:09 ` Jonathan Nieder 2010-07-31 3:28 ` [PATCH 1/3] Fix sparse checkout not removing files from index Nguyen Thai Ngoc Duy 2 siblings, 0 replies; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 1:09 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano When narrowing the checkout pattern to exclude a file that the merge was going to delete, read-tree decides two wrongs make a right and leaves the file behind. Or that’s what it looks like. Actually, for some reason apply_sparse_checkout() is not paying proper attention to entries removed by the merge, so they look like ordinary deletions outside the sparse area. While fixing that, clarify the semantics of the unpack-trees flags: - CE_UPDATE marks an entry for which the worktree might need to be updated to match. If CE_UPDATE is not set, changes only apply to the index file. - CE_REMOVE marks an entry removed by the merge (just like it did before). - CE_WT_REMOVE marks an entry that no longer matches the sparse pattern. Cc: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> --- Sorry for the lack of clarity before. This is just to give the idea; I have no confidence that I am not breaking something, especially because I have not checked why the "if" I am removing in apply_sparse_checkout was added. cache.h | 3 +- t/t1011-read-tree-sparse-checkout.sh | 21 +++++++++++++++++ unpack-trees.c | 42 +++++++++------------------------ 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/cache.h b/cache.h index 3c7fb6f..c9fa3df 100644 --- a/cache.h +++ b/cache.h @@ -179,7 +179,8 @@ struct cache_entry { #define CE_UNHASHED (0x200000) #define CE_CONFLICTED (0x800000) -#define CE_WT_REMOVE (0x400000) /* remove in work directory */ +/* Only remove in work directory, not index */ +#define CE_WT_REMOVE (0x400000) #define CE_UNPACKED (0x1000000) diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 2955071..247f295 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -155,6 +155,27 @@ test_expect_failure 'read-tree adds to worktree, dirty case' ' grep -q dirty sub/added ' +test_expect_success 'narrow checkout while removing file' ' + echo "H init.t" >expected.swt-after && + printf "%s\n" init.t sub/added | sort >expected.ls-before + echo init.t >expected.ls-after && + + printf "%s\n" init.t sub/added >.git/info/sparse-checkout && + git checkout -f top && + git ls-files -t >index.before && + ls init.t sub/added | sort >worktree.before && + + echo init.t >.git/info/sparse-checkout && + git read-tree -m -u HEAD^ && + git ls-files -t >index.after && + ls init.t sub/added | sort >worktree.after && + + test_cmp expected.swt index.before && + test_cmp expected.swt-after index.after && + test_cmp expected.ls-before worktree.before && + test_cmp expected.ls-after worktree.after +' + test_expect_success 'read-tree --reset removes outside worktree' ' >empty && echo init.t >.git/info/sparse-checkout && diff --git a/unpack-trees.c b/unpack-trees.c index 523e1de..deabfd9 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -53,9 +53,6 @@ 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; @@ -87,7 +84,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_WT_REMOVE)) + if (ce->ce_flags & CE_UPDATE) total++; } @@ -101,11 +98,12 @@ 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_WT_REMOVE) { + if (ce->ce_flags & CE_UPDATE && + ce->ce_flags & (CE_REMOVE | CE_WT_REMOVE)) { display_progress(progress, ++cnt); + ce->ce_flags &= ~CE_UPDATE & ~CE_WT_REMOVE; if (o->update) unlink_entry(ce); - continue; } } remove_marked_cache_entries(&o->result); @@ -152,15 +150,6 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt else ce->ce_flags &= ~CE_SKIP_WORKTREE; - /* - * We only care about files getting into the checkout area - * If merge strategies want to remove some, go ahead, this - * flag will be removed eventually in unpack_trees() if it's - * outside checkout area. - */ - if (ce->ce_flags & CE_REMOVE) - return 0; - if (!was_skip_worktree && ce_skip_worktree(ce)) { /* * If CE_UPDATE is set, verify_uptodate() must be called already @@ -169,7 +158,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt */ if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o)) return -1; - ce->ce_flags |= CE_WT_REMOVE; + ce->ce_flags |= CE_WT_REMOVE | CE_UPDATE; } if (was_skip_worktree && !ce_skip_worktree(ce)) { if (verify_absent_sparse(ce, "overwritten", o)) @@ -796,20 +785,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options goto done; } /* - * 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(). - * Make sure they don't modify worktree. + * Do not modify worktree outside of sparse checkout area, + * except to make the checkout more narrow. */ - if (ce_skip_worktree(ce)) { - ce->ce_flags &= ~CE_UPDATE; - - if (ce->ce_flags & CE_REMOVE) - ce->ce_flags &= ~CE_WT_REMOVE; - } - else + if (!ce_skip_worktree(ce)) empty_worktree = 0; - + else if (!(ce->ce_flags & CE_WT_REMOVE)) + ce->ce_flags &= ~CE_UPDATE; } if (o->result.cache_nr && empty_worktree) { ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory"); @@ -968,7 +950,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, if (!ce_stage(ce2)) { if (verify_uptodate(ce2, o)) return -1; - add_entry(o, ce2, CE_REMOVE, 0); + add_entry(o, ce2, CE_REMOVE|CE_UPDATE, 0); mark_ce_used(ce2, o); } cnt++; @@ -1138,7 +1120,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, } if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o)) return -1; - add_entry(o, ce, CE_REMOVE, 0); + add_entry(o, ce, CE_REMOVE|CE_UPDATE, 0); invalidate_ce_path(ce, o); return 1; } -- 1.7.2.1.544.ga752d.dirty ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-31 1:04 ` Jonathan Nieder 2010-07-31 1:05 ` [PATCH 1/2] t1011 (sparse checkout): style nitpicks Jonathan Nieder 2010-07-31 1:09 ` [PATCH 2/2] read-tree -m -u: always remove relevant files when narrowing checkout Jonathan Nieder @ 2010-07-31 3:28 ` Nguyen Thai Ngoc Duy 2010-07-31 3:33 ` Jonathan Nieder 2 siblings, 1 reply; 17+ messages in thread From: Nguyen Thai Ngoc Duy @ 2010-07-31 3:28 UTC (permalink / raw) To: Jonathan Nieder; +Cc: git, Junio C Hamano On Sat, Jul 31, 2010 at 11:04 AM, Jonathan Nieder <jrnieder@gmail.com> wrote: > Jonathan Nieder wrote: > >> What happens if an index entry is removed at the same time as the >> checkout is narrowed? > > Hm, maybe something like this would help. Or maybe we should move the CE_UPDATE/CE_WT_REMOVE removal code into apply_sparse_checkout(). That function knows when checkout area is narrowed and CE_WT_REMOVE should not be removed in that case, regardless CE_REMOVE|CE_WT_REMOVE combination. -- Duy ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-31 3:28 ` [PATCH 1/3] Fix sparse checkout not removing files from index Nguyen Thai Ngoc Duy @ 2010-07-31 3:33 ` Jonathan Nieder 2010-07-31 3:48 ` Nguyen Thai Ngoc Duy 0 siblings, 1 reply; 17+ messages in thread From: Jonathan Nieder @ 2010-07-31 3:33 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: git, Junio C Hamano Nguyen Thai Ngoc Duy wrote: > maybe we should move the CE_UPDATE/CE_WT_REMOVE removal code into > apply_sparse_checkout(). Not a bad idea regardless. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/3] Fix sparse checkout not removing files from index 2010-07-31 3:33 ` Jonathan Nieder @ 2010-07-31 3:48 ` Nguyen Thai Ngoc Duy 0 siblings, 0 replies; 17+ messages in thread From: Nguyen Thai Ngoc Duy @ 2010-07-31 3:48 UTC (permalink / raw) To: Jonathan Nieder; +Cc: git, Junio C Hamano On Sat, Jul 31, 2010 at 1:33 PM, Jonathan Nieder <jrnieder@gmail.com> wrote: > Nguyen Thai Ngoc Duy wrote: > >> maybe we should move the CE_UPDATE/CE_WT_REMOVE removal code into >> apply_sparse_checkout(). > > Not a bad idea regardless. Yeah, something like this, perhaps. It's not tested. I'll repost the patch later, incorporating all your suggestions. diff --git a/unpack-trees.c b/unpack-trees.c index f2d148c..48654b3 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -153,6 +153,26 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt ce->ce_flags &= ~CE_SKIP_WORKTREE; /* + * 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(). + * Make sure they don't modify worktree if they are already + * outside checkout area + */ + if (was_skip_worktree && ce_skip_worktree(ce)) { + ce->ce_flags &= ~CE_UPDATE; + + /* + * By default, when CE_REMOVE is on, CE_WT_REMOVE is also + * on to get that file removed from both index and worktree. + * If that file is already outside worktree area, don't + * bother remove it. + */ + if (ce->ce_flags & CE_REMOVE) + ce->ce_flags &= ~CE_WT_REMOVE; + } + + /* * We only care about files getting into the checkout area * If merge strategies want to remove some, go ahead, this * flag will be removed eventually in unpack_trees() if it's @@ -793,19 +813,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options ret = -1; goto done; } - /* - * 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(). - * Make sure they don't modify worktree. - */ - if (ce_skip_worktree(ce)) { - ce->ce_flags &= ~CE_UPDATE; - - if (ce->ce_flags & CE_REMOVE) - ce->ce_flags &= ~CE_WT_REMOVE; - } - else + if (!ce_skip_worktree(ce)) empty_worktree = 0; } -- Duy ^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2010-07-31 3:48 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-07-26 9:08 [PATCH 1/3] Fix sparse checkout not removing files from index Nguyễn Thái Ngọc Duy 2010-07-26 9:08 ` [PATCH 2/3] unpack-trees.c: Do not check ce_stage in will_have_skip_worktree() Nguyễn Thái Ngọc Duy 2010-07-31 2:11 ` Jonathan Nieder 2010-07-31 3:12 ` Nguyen Thai Ngoc Duy 2010-07-26 9:08 ` [PATCH 3/3] Mark new entries skip-worktree appropriately Nguyễn Thái Ngọc Duy 2010-07-31 2:32 ` Jonathan Nieder 2010-07-31 3:13 ` Nguyen Thai Ngoc Duy 2010-07-31 3:29 ` Jonathan Nieder 2010-07-30 1:35 ` [PATCH 1/3] Fix sparse checkout not removing files from index Jonathan Nieder 2010-07-30 8:24 ` Nguyen Thai Ngoc Duy 2010-07-30 19:50 ` Jonathan Nieder 2010-07-31 1:04 ` Jonathan Nieder 2010-07-31 1:05 ` [PATCH 1/2] t1011 (sparse checkout): style nitpicks Jonathan Nieder 2010-07-31 1:09 ` [PATCH 2/2] read-tree -m -u: always remove relevant files when narrowing checkout Jonathan Nieder 2010-07-31 3:28 ` [PATCH 1/3] Fix sparse checkout not removing files from index Nguyen Thai Ngoc Duy 2010-07-31 3:33 ` Jonathan Nieder 2010-07-31 3:48 ` Nguyen Thai Ngoc Duy
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.