{"thread":{"id":"39981","subject":"[PATCH] untracked-cache: support sparse checkout","startedAt":"2015-07-31T17:35:01Z","lastAt":"2015-08-03T10:23:01Z","messageCount":3,"participants":["David Turner","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"267204","messageId":"1438364101-6597-1-git-send-email-dturner@twopensource.com","threadId":"39981","inReplyTo":null,"subject":"[PATCH] untracked-cache: support sparse checkout","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-07-31T17:35:01Z","receivedAt":"2015-07-31T17:35:01Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Remove a check that would disable the untracked cache for sparse\ncheckouts.  Add tests that ensure that the untracked cache works with\nsparse checkouts -- specifically considering the case that a file\nfoo/bar is checked out, but foo/.gitignore is not.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n dir.c                             |  17 +-----\n t/t7063-status-untracked-cache.sh | 119 ++++++++++++++++++++++++++++++++++++++\n 2 files changed, 122 insertions(+), 14 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 8209f8b..e7b89fe 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1078,10 +1078,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\t    (!untracked || !untracked->valid ||\n \t\t     /*\n \t\t      * .. and .gitignore does not exist before\n-\t\t      * (i.e. null exclude_sha1 and skip_worktree is\n-\t\t      * not set). Then we can skip loading .gitignore,\n-\t\t      * which would result in ENOENT anyway.\n-\t\t      * skip_worktree is taken care in read_directory()\n+\t\t      * (i.e. null exclude_sha1). Then we can skip\n+\t\t      * loading .gitignore, which would result in\n+\t\t      * ENOENT anyway.\n \t\t      */\n \t\t     !is_null_sha1(untracked->exclude_sha1))) {\n \t\t\t/*\n@@ -1880,7 +1879,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \t\t\t\t\t\t      const struct pathspec *pathspec)\n {\n \tstruct untracked_cache_dir *root;\n-\tint i;\n \n \tif (!dir->untracked || getenv(\"GIT_DISABLE_UNTRACKED_CACHE\"))\n \t\treturn NULL;\n@@ -1932,15 +1930,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \tif (dir->exclude_list_group[EXC_CMDL].nr)\n \t\treturn NULL;\n \n-\t/*\n-\t * An optimization in prep_exclude() does not play well with\n-\t * CE_SKIP_WORKTREE. It's a rare case anyway, if a single\n-\t * entry has that bit set, disable the whole untracked cache.\n-\t */\n-\tfor (i = 0; i < active_nr; i++)\n-\t\tif (ce_skip_worktree(active_cache[i]))\n-\t\t\treturn NULL;\n-\n \tif (!ident_in_untracked(dir->untracked)) {\n \t\twarning(_(\"Untracked cache is disabled on this system.\"));\n \t\treturn NULL;\ndiff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh\nindex bd4806c..ff23f4e 100755\n--- a/t/t7063-status-untracked-cache.sh\n+++ b/t/t7063-status-untracked-cache.sh\n@@ -354,4 +354,123 @@ EOF\n \ttest_cmp ../expect ../actual\n '\n \n+test_expect_success 'set up for sparse checkout testing' '\n+\techo two >done/.gitignore &&\n+\techo three >>done/.gitignore &&\n+\techo two >done/two &&\n+\tgit add -f done/two done/.gitignore &&\n+\tgit commit -m \"first commit\"\n+'\n+\n+test_expect_success 'status after commit' '\n+\t: >../trace &&\n+\tGIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n+\tgit status --porcelain >../actual &&\n+\tcat >../status.expect <<EOF &&\n+?? .gitignore\n+?? dtwo/\n+EOF\n+\ttest_cmp ../status.expect ../actual &&\n+\tcat >../trace.expect <<EOF &&\n+node creation: 0\n+gitignore invalidation: 0\n+directory invalidation: 0\n+opendir: 1\n+EOF\n+\ttest_cmp ../trace.expect ../trace\n+'\n+\n+test_expect_success 'untracked cache correct after commit' '\n+\ttest-dump-untracked-cache >../actual &&\n+\tcat >../expect <<EOF &&\n+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n+core.excludesfile 0000000000000000000000000000000000000000\n+exclude_per_dir .gitignore\n+flags 00000006\n+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n+.gitignore\n+dtwo/\n+/done/ 0000000000000000000000000000000000000000 recurse valid\n+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n+two\n+EOF\n+\ttest_cmp ../expect ../actual\n+'\n+\n+test_expect_success 'set up sparse checkout' '\n+\techo \"done/[a-z]*\" >.git/info/sparse-checkout &&\n+\ttest_config core.sparsecheckout true &&\n+\tgit checkout master &&\n+\tgit update-index --untracked-cache &&\n+\tgit status --porcelain >/dev/null && # prime the cache\n+\ttest_path_is_missing done/.gitignore &&\n+\ttest_path_is_file done/one\n+'\n+\n+test_expect_success 'create files, some of which are gitignored' '\n+\techo three >done/three && # three is gitignored\n+\techo four >done/four && # four is gitignored at a higher level\n+\techo five >done/five # five is not gitignored\n+'\n+\n+test_expect_success 'test sparse status with untracked cache' '\n+\t: >../trace &&\n+\tavoid_racy &&\n+\tGIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n+\tgit status --porcelain >../status.actual &&\n+\tcat >../status.expect <<EOF &&\n+?? .gitignore\n+?? done/five\n+?? dtwo/\n+EOF\n+\ttest_cmp ../status.expect ../status.actual &&\n+\tcat >../trace.expect <<EOF &&\n+node creation: 0\n+gitignore invalidation: 1\n+directory invalidation: 2\n+opendir: 2\n+EOF\n+\ttest_cmp ../trace.expect ../trace\n+'\n+\n+test_expect_success 'untracked cache correct after status' '\n+\ttest-dump-untracked-cache >../actual &&\n+\tcat >../expect <<EOF &&\n+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n+core.excludesfile 0000000000000000000000000000000000000000\n+exclude_per_dir .gitignore\n+flags 00000006\n+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n+.gitignore\n+dtwo/\n+/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid\n+five\n+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n+two\n+EOF\n+\ttest_cmp ../expect ../actual\n+'\n+\n+test_expect_success 'test sparse status again with untracked cache' '\n+\tavoid_racy &&\n+\t: >../trace &&\n+\tGIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n+\tgit status --porcelain >../status.actual &&\n+\tcat >../status.expect <<EOF &&\n+?? .gitignore\n+?? done/five\n+?? dtwo/\n+EOF\n+\ttest_cmp ../status.expect ../status.actual &&\n+\tcat >../trace.expect <<EOF &&\n+node creation: 0\n+gitignore invalidation: 0\n+directory invalidation: 0\n+opendir: 0\n+EOF\n+\ttest_cmp ../trace.expect ../trace\n+'\n+\n test_done\n-- \n2.0.4.315.gad8727a-twtrsrc\n"},{"id":"267303","messageId":"CACsJy8C6TiwQQKsaaMTZpAcgC=ma-yW5AR5i7vZnx6JBWSjRTA@mail.gmail.com","threadId":"39981","inReplyTo":"1438364101-6597-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH] untracked-cache: support sparse checkout","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-08-03T10:18:06Z","receivedAt":"2015-08-03T10:18:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Aug 1, 2015 at 12:35 AM, David Turner <dturner@twopensource.com> wrote:\n> Remove a check that would disable the untracked cache for sparse\n> checkouts.  Add tests that ensure that the untracked cache works with\n> sparse checkouts -- specifically considering the case that a file\n> foo/bar is checked out, but foo/.gitignore is not.\n\nI have looked some more at the code (sorry for being slow these days,\n$DAY_JOB can be exhausting). The reason 27b099a (untracked cache:\ndon't open non-existent .gitignore - 2015-03-08) avoids skip-worktree\nis because when that patch is added, index changes do not affect\nuntracked cache (yet). So when you delete the on-worktree .gitignore,\nuntracked cache is invalidated and it falls back to the index version.\nexclude_sha1 would reflect the content in the index. If the in-index\n.gitignore is deleted, without feedback from the index, untracked\ncache remains unchanged (i.e. valid) and assumes that .gitignore is\nstill there. Which is wrong. That's fixed in e931371 (untracked cache:\ninvalidate at index addition or removal - 2015-03-08).\n\nWith that out of the way,\n\nAcked-by: Duy Nguyen <pclouds@gmail.com>\n\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  dir.c                             |  17 +-----\n>  t/t7063-status-untracked-cache.sh | 119 ++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 122 insertions(+), 14 deletions(-)\n>\n> diff --git a/dir.c b/dir.c\n> index 8209f8b..e7b89fe 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -1078,10 +1078,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n>                     (!untracked || !untracked->valid ||\n>                      /*\n>                       * .. and .gitignore does not exist before\n> -                     * (i.e. null exclude_sha1 and skip_worktree is\n> -                     * not set). Then we can skip loading .gitignore,\n> -                     * which would result in ENOENT anyway.\n> -                     * skip_worktree is taken care in read_directory()\n> +                     * (i.e. null exclude_sha1). Then we can skip\n> +                     * loading .gitignore, which would result in\n> +                     * ENOENT anyway.\n>                       */\n>                      !is_null_sha1(untracked->exclude_sha1))) {\n>                         /*\n> @@ -1880,7 +1879,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n>                                                       const struct pathspec *pathspec)\n>  {\n>         struct untracked_cache_dir *root;\n> -       int i;\n>\n>         if (!dir->untracked || getenv(\"GIT_DISABLE_UNTRACKED_CACHE\"))\n>                 return NULL;\n> @@ -1932,15 +1930,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n>         if (dir->exclude_list_group[EXC_CMDL].nr)\n>                 return NULL;\n>\n> -       /*\n> -        * An optimization in prep_exclude() does not play well with\n> -        * CE_SKIP_WORKTREE. It's a rare case anyway, if a single\n> -        * entry has that bit set, disable the whole untracked cache.\n> -        */\n> -       for (i = 0; i < active_nr; i++)\n> -               if (ce_skip_worktree(active_cache[i]))\n> -                       return NULL;\n> -\n>         if (!ident_in_untracked(dir->untracked)) {\n>                 warning(_(\"Untracked cache is disabled on this system.\"));\n>                 return NULL;\n> diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh\n> index bd4806c..ff23f4e 100755\n> --- a/t/t7063-status-untracked-cache.sh\n> +++ b/t/t7063-status-untracked-cache.sh\n> @@ -354,4 +354,123 @@ EOF\n>         test_cmp ../expect ../actual\n>  '\n>\n> +test_expect_success 'set up for sparse checkout testing' '\n> +       echo two >done/.gitignore &&\n> +       echo three >>done/.gitignore &&\n> +       echo two >done/two &&\n> +       git add -f done/two done/.gitignore &&\n> +       git commit -m \"first commit\"\n> +'\n> +\n> +test_expect_success 'status after commit' '\n> +       : >../trace &&\n> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n> +       git status --porcelain >../actual &&\n> +       cat >../status.expect <<EOF &&\n> +?? .gitignore\n> +?? dtwo/\n> +EOF\n> +       test_cmp ../status.expect ../actual &&\n> +       cat >../trace.expect <<EOF &&\n> +node creation: 0\n> +gitignore invalidation: 0\n> +directory invalidation: 0\n> +opendir: 1\n> +EOF\n> +       test_cmp ../trace.expect ../trace\n> +'\n> +\n> +test_expect_success 'untracked cache correct after commit' '\n> +       test-dump-untracked-cache >../actual &&\n> +       cat >../expect <<EOF &&\n> +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n> +core.excludesfile 0000000000000000000000000000000000000000\n> +exclude_per_dir .gitignore\n> +flags 00000006\n> +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n> +.gitignore\n> +dtwo/\n> +/done/ 0000000000000000000000000000000000000000 recurse valid\n> +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n> +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n> +two\n> +EOF\n> +       test_cmp ../expect ../actual\n> +'\n> +\n> +test_expect_success 'set up sparse checkout' '\n> +       echo \"done/[a-z]*\" >.git/info/sparse-checkout &&\n> +       test_config core.sparsecheckout true &&\n> +       git checkout master &&\n> +       git update-index --untracked-cache &&\n> +       git status --porcelain >/dev/null && # prime the cache\n> +       test_path_is_missing done/.gitignore &&\n> +       test_path_is_file done/one\n> +'\n> +\n> +test_expect_success 'create files, some of which are gitignored' '\n> +       echo three >done/three && # three is gitignored\n> +       echo four >done/four && # four is gitignored at a higher level\n> +       echo five >done/five # five is not gitignored\n> +'\n> +\n> +test_expect_success 'test sparse status with untracked cache' '\n> +       : >../trace &&\n> +       avoid_racy &&\n> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n> +       git status --porcelain >../status.actual &&\n> +       cat >../status.expect <<EOF &&\n> +?? .gitignore\n> +?? done/five\n> +?? dtwo/\n> +EOF\n> +       test_cmp ../status.expect ../status.actual &&\n> +       cat >../trace.expect <<EOF &&\n> +node creation: 0\n> +gitignore invalidation: 1\n> +directory invalidation: 2\n> +opendir: 2\n> +EOF\n> +       test_cmp ../trace.expect ../trace\n> +'\n> +\n> +test_expect_success 'untracked cache correct after status' '\n> +       test-dump-untracked-cache >../actual &&\n> +       cat >../expect <<EOF &&\n> +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n> +core.excludesfile 0000000000000000000000000000000000000000\n> +exclude_per_dir .gitignore\n> +flags 00000006\n> +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n> +.gitignore\n> +dtwo/\n> +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid\n> +five\n> +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n> +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n> +two\n> +EOF\n> +       test_cmp ../expect ../actual\n> +'\n> +\n> +test_expect_success 'test sparse status again with untracked cache' '\n> +       avoid_racy &&\n> +       : >../trace &&\n> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n> +       git status --porcelain >../status.actual &&\n> +       cat >../status.expect <<EOF &&\n> +?? .gitignore\n> +?? done/five\n> +?? dtwo/\n> +EOF\n> +       test_cmp ../status.expect ../status.actual &&\n> +       cat >../trace.expect <<EOF &&\n> +node creation: 0\n> +gitignore invalidation: 0\n> +directory invalidation: 0\n> +opendir: 0\n> +EOF\n> +       test_cmp ../trace.expect ../trace\n> +'\n> +\n>  test_done\n> --\n> 2.0.4.315.gad8727a-twtrsrc\n>\n\n\n\n-- \nDuy\n"},{"id":"267305","messageId":"CACsJy8AjDzkGW9MnkJX7GVof4+czm-sbHQhD7F5TFKg16NxAgg@mail.gmail.com","threadId":"39981","inReplyTo":"CACsJy8C6TiwQQKsaaMTZpAcgC=ma-yW5AR5i7vZnx6JBWSjRTA@mail.gmail.com","subject":"Re: [PATCH] untracked-cache: support sparse checkout","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-08-03T10:23:01Z","receivedAt":"2015-08-03T10:23:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Aug 3, 2015 at 5:18 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Sat, Aug 1, 2015 at 12:35 AM, David Turner <dturner@twopensource.com> wrote:\n>> Remove a check that would disable the untracked cache for sparse\n>> checkouts.  Add tests that ensure that the untracked cache works with\n>> sparse checkouts -- specifically considering the case that a file\n>> foo/bar is checked out, but foo/.gitignore is not.\n>\n> I have looked some more at the code (sorry for being slow these days,\n> $DAY_JOB can be exhausting). The reason 27b099a (untracked cache:\n> don't open non-existent .gitignore - 2015-03-08) avoids skip-worktree\n> is because when that patch is added, index changes do not affect\n> untracked cache (yet). So when you delete the on-worktree .gitignore,\n> untracked cache is invalidated and it falls back to the index version.\n> exclude_sha1 would reflect the content in the index. If the in-index\n> .gitignore is deleted, without feedback from the index, untracked\n> cache remains unchanged (i.e. valid) and assumes that .gitignore is\n> still there. Which is wrong.\n\nHmm.. I got it backward: it should be like this: delete .gitignore on\nworktree and in index, exclude_sha1 is null. then add .gitignore in\nindex only. exclude_sha1 remains null because the cache is still valid\neven though we should .gitignore from the index.\n\n> That's fixed in e931371 (untracked cache:\n> invalidate at index addition or removal - 2015-03-08).\n>\n> With that out of the way,\n>\n> Acked-by: Duy Nguyen <pclouds@gmail.com>\n>\n>> Signed-off-by: David Turner <dturner@twopensource.com>\n>> ---\n>>  dir.c                             |  17 +-----\n>>  t/t7063-status-untracked-cache.sh | 119 ++++++++++++++++++++++++++++++++++++++\n>>  2 files changed, 122 insertions(+), 14 deletions(-)\n>>\n>> diff --git a/dir.c b/dir.c\n>> index 8209f8b..e7b89fe 100644\n>> --- a/dir.c\n>> +++ b/dir.c\n>> @@ -1078,10 +1078,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n>>                     (!untracked || !untracked->valid ||\n>>                      /*\n>>                       * .. and .gitignore does not exist before\n>> -                     * (i.e. null exclude_sha1 and skip_worktree is\n>> -                     * not set). Then we can skip loading .gitignore,\n>> -                     * which would result in ENOENT anyway.\n>> -                     * skip_worktree is taken care in read_directory()\n>> +                     * (i.e. null exclude_sha1). Then we can skip\n>> +                     * loading .gitignore, which would result in\n>> +                     * ENOENT anyway.\n>>                       */\n>>                      !is_null_sha1(untracked->exclude_sha1))) {\n>>                         /*\n>> @@ -1880,7 +1879,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n>>                                                       const struct pathspec *pathspec)\n>>  {\n>>         struct untracked_cache_dir *root;\n>> -       int i;\n>>\n>>         if (!dir->untracked || getenv(\"GIT_DISABLE_UNTRACKED_CACHE\"))\n>>                 return NULL;\n>> @@ -1932,15 +1930,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n>>         if (dir->exclude_list_group[EXC_CMDL].nr)\n>>                 return NULL;\n>>\n>> -       /*\n>> -        * An optimization in prep_exclude() does not play well with\n>> -        * CE_SKIP_WORKTREE. It's a rare case anyway, if a single\n>> -        * entry has that bit set, disable the whole untracked cache.\n>> -        */\n>> -       for (i = 0; i < active_nr; i++)\n>> -               if (ce_skip_worktree(active_cache[i]))\n>> -                       return NULL;\n>> -\n>>         if (!ident_in_untracked(dir->untracked)) {\n>>                 warning(_(\"Untracked cache is disabled on this system.\"));\n>>                 return NULL;\n>> diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh\n>> index bd4806c..ff23f4e 100755\n>> --- a/t/t7063-status-untracked-cache.sh\n>> +++ b/t/t7063-status-untracked-cache.sh\n>> @@ -354,4 +354,123 @@ EOF\n>>         test_cmp ../expect ../actual\n>>  '\n>>\n>> +test_expect_success 'set up for sparse checkout testing' '\n>> +       echo two >done/.gitignore &&\n>> +       echo three >>done/.gitignore &&\n>> +       echo two >done/two &&\n>> +       git add -f done/two done/.gitignore &&\n>> +       git commit -m \"first commit\"\n>> +'\n>> +\n>> +test_expect_success 'status after commit' '\n>> +       : >../trace &&\n>> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n>> +       git status --porcelain >../actual &&\n>> +       cat >../status.expect <<EOF &&\n>> +?? .gitignore\n>> +?? dtwo/\n>> +EOF\n>> +       test_cmp ../status.expect ../actual &&\n>> +       cat >../trace.expect <<EOF &&\n>> +node creation: 0\n>> +gitignore invalidation: 0\n>> +directory invalidation: 0\n>> +opendir: 1\n>> +EOF\n>> +       test_cmp ../trace.expect ../trace\n>> +'\n>> +\n>> +test_expect_success 'untracked cache correct after commit' '\n>> +       test-dump-untracked-cache >../actual &&\n>> +       cat >../expect <<EOF &&\n>> +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n>> +core.excludesfile 0000000000000000000000000000000000000000\n>> +exclude_per_dir .gitignore\n>> +flags 00000006\n>> +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n>> +.gitignore\n>> +dtwo/\n>> +/done/ 0000000000000000000000000000000000000000 recurse valid\n>> +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n>> +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n>> +two\n>> +EOF\n>> +       test_cmp ../expect ../actual\n>> +'\n>> +\n>> +test_expect_success 'set up sparse checkout' '\n>> +       echo \"done/[a-z]*\" >.git/info/sparse-checkout &&\n>> +       test_config core.sparsecheckout true &&\n>> +       git checkout master &&\n>> +       git update-index --untracked-cache &&\n>> +       git status --porcelain >/dev/null && # prime the cache\n>> +       test_path_is_missing done/.gitignore &&\n>> +       test_path_is_file done/one\n>> +'\n>> +\n>> +test_expect_success 'create files, some of which are gitignored' '\n>> +       echo three >done/three && # three is gitignored\n>> +       echo four >done/four && # four is gitignored at a higher level\n>> +       echo five >done/five # five is not gitignored\n>> +'\n>> +\n>> +test_expect_success 'test sparse status with untracked cache' '\n>> +       : >../trace &&\n>> +       avoid_racy &&\n>> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n>> +       git status --porcelain >../status.actual &&\n>> +       cat >../status.expect <<EOF &&\n>> +?? .gitignore\n>> +?? done/five\n>> +?? dtwo/\n>> +EOF\n>> +       test_cmp ../status.expect ../status.actual &&\n>> +       cat >../trace.expect <<EOF &&\n>> +node creation: 0\n>> +gitignore invalidation: 1\n>> +directory invalidation: 2\n>> +opendir: 2\n>> +EOF\n>> +       test_cmp ../trace.expect ../trace\n>> +'\n>> +\n>> +test_expect_success 'untracked cache correct after status' '\n>> +       test-dump-untracked-cache >../actual &&\n>> +       cat >../expect <<EOF &&\n>> +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0\n>> +core.excludesfile 0000000000000000000000000000000000000000\n>> +exclude_per_dir .gitignore\n>> +flags 00000006\n>> +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid\n>> +.gitignore\n>> +dtwo/\n>> +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid\n>> +five\n>> +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid\n>> +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid\n>> +two\n>> +EOF\n>> +       test_cmp ../expect ../actual\n>> +'\n>> +\n>> +test_expect_success 'test sparse status again with untracked cache' '\n>> +       avoid_racy &&\n>> +       : >../trace &&\n>> +       GIT_TRACE_UNTRACKED_STATS=\"$TRASH_DIRECTORY/trace\" \\\n>> +       git status --porcelain >../status.actual &&\n>> +       cat >../status.expect <<EOF &&\n>> +?? .gitignore\n>> +?? done/five\n>> +?? dtwo/\n>> +EOF\n>> +       test_cmp ../status.expect ../status.actual &&\n>> +       cat >../trace.expect <<EOF &&\n>> +node creation: 0\n>> +gitignore invalidation: 0\n>> +directory invalidation: 0\n>> +opendir: 0\n>> +EOF\n>> +       test_cmp ../trace.expect ../trace\n>> +'\n>> +\n>>  test_done\n>> --\n>> 2.0.4.315.gad8727a-twtrsrc\n>>\n>\n>\n>\n> --\n> Duy\n\n\n\n-- \nDuy\n"}]}