2011/5/2 Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx>: > Sparse-setting code follows closely how files are excluded in > read_directory(), every entry (including directories) are fed to > excluded_from_list() to decide if the entry is suitable. Directories > are treated no different than files. If a directory is matched (or > not), the whole directory is considered matched (or not) and the > process moves on. > > This generally works as long as there are no patterns to exclude parts > of the directory. In case of sparse checkout code, the following patterns > > Ât > Â!t/t0000-basic.sh > > will produce a worktree with full directory "t" even if t0000-basic.sh > is requested to stay out. > > By the same reasoning, if a directory is to be excluded, any rules to > re-include certain files within that directory will be ignored. > > Fix it by always checking files against patterns. If no pattern can > decide (ie. excluded_from_list() returns -1), those files will be Maybe: can be decided? > included/excluded as same as their parent directory. > > Noticed-by: <skillzero@xxxxxxxxx> > Signed-off-by: Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx> > --- > ÂThe TODO better be solved once read_directory() fixes the same fault. > ÂI have a feeling that some code can be shared.. > > Ât/t1011-read-tree-sparse-checkout.sh |  41 ++++++++++++++++++++++ > Âunpack-trees.c            |  63 ++++++++++++++++++--------------- > Â2 files changed, 75 insertions(+), 29 deletions(-) > > diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh > index 3f9d66f..20a50eb 100755 > --- a/t/t1011-read-tree-sparse-checkout.sh > +++ b/t/t1011-read-tree-sparse-checkout.sh > @@ -106,6 +106,47 @@ test_expect_success 'match directories without trailing slash' ' >    Âtest -f sub/added > Â' > > +test_expect_success 'match directories with negated patterns' ' > +    cat >expected.swt-negation <<\EOF && > +S init.t > +S sub/added > +H sub/addedtoo > +S subsub/added > +EOF > + > +    cat >.git/info/sparse-checkout <<\EOF && > +sub > +!sub/added > +EOF > +    git read-tree -m -u HEAD && > +    git ls-files -t >result && > +    test_cmp expected.swt-negation result && > +    test ! -f init.t && > +    test ! -f sub/added && > +    test -f sub/addedtoo > +' > + > +test_expect_success 'match directories with negated patterns (2)' ' > +    cat >expected.swt-negation2 <<\EOF && > +H init.t > +H sub/added > +S sub/addedtoo > +H subsub/added > +EOF > + > +    cat >.git/info/sparse-checkout <<\EOF && > +/* > +!sub > +sub/added > +EOF > +    git read-tree -m -u HEAD && > +    git ls-files -t >result && > +    test_cmp expected.swt-negation2 result && > +    test -f init.t && > +    test -f sub/added && > +    test ! -f sub/addedtoo > +' > + > Âtest_expect_success 'match directory pattern' ' >    Âecho "s?b" >.git/info/sparse-checkout && >    Âgit read-tree -m -u HEAD && > diff --git a/unpack-trees.c b/unpack-trees.c > index 500ebcf..5b8419c 100644 > --- a/unpack-trees.c > +++ b/unpack-trees.c > @@ -814,43 +814,45 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str >    Âreturn mask; > Â} > > +static int clear_ce_flags_1(struct cache_entry **cache, int nr, > +              char *prefix, int prefix_len, > +              int select_mask, int clear_mask, > +              struct exclude_list *el, int defval); > + > Â/* Whole directory matching */ > Âstatic int clear_ce_flags_dir(struct cache_entry **cache, int nr, >               Âchar *prefix, int prefix_len, >               Âchar *basename, >               Âint select_mask, int clear_mask, > -               struct exclude_list *el) > +               struct exclude_list *el, int defval) > Â{ > -    struct cache_entry **cache_end = cache + nr; > +    struct cache_entry **cache_end; >    Âint dtype = DT_DIR; >    Âint ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el); > >    Âprefix[prefix_len++] = '/'; > > -    /* included, no clearing for any entries under this directory */ > -    if (!ret) { > -        for (; cache != cache_end; cache++) { > -            struct cache_entry *ce = *cache; > -            if (strncmp(ce->name, prefix, prefix_len)) > -                break; > -        } > -        return nr - (cache_end - cache); > -    } > +    /* If undecided, use parent directory's decision in defval */ What means "use parent directory's decision"? Could you make this comment more clearer? > +    if (ret < 0) > +        ret = defval; > > -    /* excluded, clear all selected entries under this directory. */ Start with capital letter? > -    if (ret == 1) { > -        for (; cache != cache_end; cache++) { > -            struct cache_entry *ce = *cache; > -            if (select_mask && !(ce->ce_flags & select_mask)) > -                continue; > -            if (strncmp(ce->name, prefix, prefix_len)) > -                break; > -            ce->ce_flags &= ~clear_mask; > -        } > -        return nr - (cache_end - cache); > +    for (cache_end = cache; cache_end != cache + nr; cache_end++) { > +        struct cache_entry *ce = *cache_end; > +        if (strncmp(ce->name, prefix, prefix_len)) > +            break; >    Â} > > -    return 0; > +    /* > +    Â* TODO: check el, if there are no patterns that may conflict > +    Â* with ret (iow, we know in advance the the incl/excl the the ? > +    Â* decision for the entire directory), clear flag here without > +    Â* calling clear_ce_flags_1(). That function will call > +    Â* the expensive excluded_from_list() on every entry. > +    Â*/ > +    return clear_ce_flags_1(cache, cache_end - cache, > +                prefix, prefix_len, > +                select_mask, clear_mask, > +                el, ret); > Â} > > Â/* > @@ -871,7 +873,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, > Âstatic int clear_ce_flags_1(struct cache_entry **cache, int nr, >              Âchar *prefix, int prefix_len, >              Âint select_mask, int clear_mask, > -              struct exclude_list *el) > +              struct exclude_list *el, int defval) > Â{ >    Âstruct cache_entry **cache_end = cache + nr; > > @@ -882,7 +884,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, >    Âwhile(cache != cache_end) { >        Âstruct cache_entry *ce = *cache; >        Âconst char *name, *slash; > -        int len, dtype; > +        int len, dtype, ret; > >        Âif (select_mask && !(ce->ce_flags & select_mask)) { >            Âcache++; > @@ -911,7 +913,7 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, >                            prefix, prefix_len + len, >                            prefix + prefix_len, >                            select_mask, clear_mask, > -                           Âel); > +                           Âel, defval); > >            Â/* clear_c_f_dir eats a whole dir already? */ >            Âif (processed) { > @@ -922,13 +924,16 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, >            Âprefix[prefix_len + len++] = '/'; >            Âcache += clear_ce_flags_1(cache, cache_end - cache, >                         Âprefix, prefix_len + len, > -                         select_mask, clear_mask, el); > +                         select_mask, clear_mask, el, defval); >            Âcontinue; >        Â} > >        Â/* Non-directory */ >        Âdtype = ce_to_dtype(ce); > -        if (excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el) > 0) > +        ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el); > +        if (ret < 0) > +            ret = defval; > +        if (ret > 0) >            Âce->ce_flags &= ~clear_mask; >        Âcache++; >    Â} > @@ -943,7 +948,7 @@ static int clear_ce_flags(struct cache_entry **cache, int nr, >    Âreturn clear_ce_flags_1(cache, nr, >                Âprefix, 0, >                Âselect_mask, clear_mask, > -                el); > +                el, 0); > Â} > > Â/* > -- > 1.7.4.74.g639db > > -- > 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 > ÿô.nÇ·®+%˱é¥wÿº{.nÇ· ßØnr¡öë¨è&£ûz¹Þúzf£¢·h§~Ûÿÿïÿê_èæ+v¨þ)ßø