{"thread":{"id":"39878","subject":"[PATCH] unpack-trees: don't update files flagged for deletion","startedAt":"2015-07-17T19:48:52Z","lastAt":"2015-07-21T20:52:07Z","messageCount":8,"participants":["David Turner","Junio C Hamano","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"266263","messageId":"1437162532-31933-1-git-send-email-dturner@twopensource.com","threadId":"39878","inReplyTo":null,"subject":"[PATCH] unpack-trees: don't update files flagged for deletion","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-07-17T19:48:52Z","receivedAt":"2015-07-17T19:48:52Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Don't update files in the worktree from cache entries which are\nflagged with CE_WT_REMOVE.  This is fixes merges in sparse\ncheckouts.\n\nSigned-off-by: Anatole Shaw <git-devel@omni.poc.net>\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n\nThis patch was written by my colleague Anatole Shaw for Twitter's git;\nI just rebased it on mainstream git.  Anatole has given me permission\nto send this upstream.\n\n---\n t/t1090-sparse-checkout-scope.sh | 52 ++++++++++++++++++++++++++++++++++++++++\n unpack-trees.c                   |  2 +-\n 2 files changed, 53 insertions(+), 1 deletion(-)\n create mode 100755 t/t1090-sparse-checkout-scope.sh\n\ndiff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh\nnew file mode 100755\nindex 0000000..1f61eb3\n--- /dev/null\n+++ b/t/t1090-sparse-checkout-scope.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='sparse checkout scope tests'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo \"initial\" >a &&\n+\techo \"initial\" >b &&\n+\techo \"initial\" >c &&\n+\tgit add a b c &&\n+\tgit commit -m \"initial commit\"\n+'\n+\n+test_expect_success 'create feature branch' '\n+\tgit checkout -b feature &&\n+\techo \"modified\" >b &&\n+\techo \"modified\" >c &&\n+\tgit add b c &&\n+\tgit commit -m \"modification\"\n+'\n+\n+test_expect_success 'perform sparse checkout of master' '\n+\tgit config --local --bool core.sparsecheckout true &&\n+\techo \"!/*\" >.git/info/sparse-checkout &&\n+\techo \"/a\" >>.git/info/sparse-checkout &&\n+\techo \"/c\" >>.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c\n+'\n+\n+test_expect_success 'merge feature branch into sparse checkout of master' '\n+\tgit merge feature &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat c)\" = \"modified\"\n+'\n+\n+test_expect_success 'return to full checkout of master' '\n+\tgit checkout feature &&\n+\techo \"/*\" >.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_file b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat b)\" = \"modified\"\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 2927660..11a5300 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -223,7 +223,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tfor (i = 0; i < index->cache_nr; i++) {\n \t\tstruct cache_entry *ce = index->cache[i];\n \n-\t\tif (ce->ce_flags & CE_UPDATE) {\n+\t\tif (ce->ce_flags & CE_UPDATE && !(ce->ce_flags & CE_WT_REMOVE)) {\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tce->ce_flags &= ~CE_UPDATE;\n \t\t\tif (o->update && !o->dry_run) {\n-- \n2.0.4.315.gad8727a-twtrsrc\n"},{"id":"266264","messageId":"xmqqk2ty1reo.fsf@gitster.dls.corp.google.com","threadId":"39878","inReplyTo":"1437162532-31933-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH] unpack-trees: don't update files flagged for deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-17T20:05:19Z","receivedAt":"2015-07-17T20:05:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> Don't update files in the worktree from cache entries which are\n> flagged with CE_WT_REMOVE.  This is fixes merges in sparse\n> checkouts.\n\ns/This is/This/;\n\nBut more importantly, what is missing is \"why\" it is a good fix.\ni.e. things like:\n\n - why is it wrong to update what is marked with CE_UPDATE bit to be\n   updated in the working tree when CE_WT_REMOVE bit is on?\n\n - how that incorrect operation breaks which operation in what way?\n\n - how does the changed code fix that breakage?\n"},{"id":"266269","messageId":"1437167967-5933-1-git-send-email-dturner@twopensource.com","threadId":"39878","inReplyTo":"xmqqk2ty1reo.fsf@gitster.dls.corp.google.com","subject":"[PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-07-17T21:19:27Z","receivedAt":"2015-07-17T21:19:27Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Don't update files in the worktree from cache entries which are\nflagged with CE_WT_REMOVE.\n\nWhen a user does a sparse checkout, git removes files that are marked\nwith CE_WT_REMOVE (because they are out-of-scope for the sparse\ncheckout). If those files are also marked CE_UPDATE (for instance,\nbecause they differ in the branch that is being checked out and the\noutgoing branch), git would previously recreate them.  This patch\nprevents them from being recreated.\n\nThese erroneously-created files would also interfere with merges,\ncausing pre-merge revisions of out-of-scope files to appear in the\nworktree.\n\nSigned-off-by: Anatole Shaw <git-devel@omni.poc.net>\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n t/t1090-sparse-checkout-scope.sh | 52 ++++++++++++++++++++++++++++++++++++++++\n unpack-trees.c                   |  2 +-\n 2 files changed, 53 insertions(+), 1 deletion(-)\n create mode 100755 t/t1090-sparse-checkout-scope.sh\n\ndiff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh\nnew file mode 100755\nindex 0000000..1f61eb3\n--- /dev/null\n+++ b/t/t1090-sparse-checkout-scope.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='sparse checkout scope tests'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo \"initial\" >a &&\n+\techo \"initial\" >b &&\n+\techo \"initial\" >c &&\n+\tgit add a b c &&\n+\tgit commit -m \"initial commit\"\n+'\n+\n+test_expect_success 'create feature branch' '\n+\tgit checkout -b feature &&\n+\techo \"modified\" >b &&\n+\techo \"modified\" >c &&\n+\tgit add b c &&\n+\tgit commit -m \"modification\"\n+'\n+\n+test_expect_success 'perform sparse checkout of master' '\n+\tgit config --local --bool core.sparsecheckout true &&\n+\techo \"!/*\" >.git/info/sparse-checkout &&\n+\techo \"/a\" >>.git/info/sparse-checkout &&\n+\techo \"/c\" >>.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c\n+'\n+\n+test_expect_success 'merge feature branch into sparse checkout of master' '\n+\tgit merge feature &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat c)\" = \"modified\"\n+'\n+\n+test_expect_success 'return to full checkout of master' '\n+\tgit checkout feature &&\n+\techo \"/*\" >.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_file b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat b)\" = \"modified\"\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 2927660..11a5300 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -223,7 +223,7 @@ static int check_updates(struct unpack_trees_options *o)\n \tfor (i = 0; i < index->cache_nr; i++) {\n \t\tstruct cache_entry *ce = index->cache[i];\n \n-\t\tif (ce->ce_flags & CE_UPDATE) {\n+\t\tif (ce->ce_flags & CE_UPDATE && !(ce->ce_flags & CE_WT_REMOVE)) {\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tce->ce_flags &= ~CE_UPDATE;\n \t\t\tif (o->update && !o->dry_run) {\n-- \n2.0.4.315.gad8727a-twtrsrc\n"},{"id":"266271","messageId":"xmqqbnfa1na6.fsf@gitster.dls.corp.google.com","threadId":"39878","inReplyTo":"1437167967-5933-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-17T21:34:25Z","receivedAt":"2015-07-17T21:34:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> Don't update files in the worktree from cache entries which are\n> flagged with CE_WT_REMOVE.\n>\n> When a user does a sparse checkout, git removes files that are marked\n> with CE_WT_REMOVE (because they are out-of-scope for the sparse\n> checkout). If those files are also marked CE_UPDATE (for instance,\n> because they differ in the branch that is being checked out and the\n> outgoing branch), git would previously recreate them.  This patch\n> prevents them from being recreated.\n>\n> These erroneously-created files would also interfere with merges,\n> causing pre-merge revisions of out-of-scope files to appear in the\n> worktree.\n>\n> Signed-off-by: Anatole Shaw <git-devel@omni.poc.net>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n\nThat's much more readable and understandable ;-)\n\nDuy Cc'ed for final sanity check and possiible extra comments.\n\nThanks.\n\n>  t/t1090-sparse-checkout-scope.sh | 52 ++++++++++++++++++++++++++++++++++++++++\n>  unpack-trees.c                   |  2 +-\n>  2 files changed, 53 insertions(+), 1 deletion(-)\n>  create mode 100755 t/t1090-sparse-checkout-scope.sh\n>\n> diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh\n> new file mode 100755\n> index 0000000..1f61eb3\n> --- /dev/null\n> +++ b/t/t1090-sparse-checkout-scope.sh\n> @@ -0,0 +1,52 @@\n> +#!/bin/sh\n> +\n> +test_description='sparse checkout scope tests'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup' '\n> +\techo \"initial\" >a &&\n> +\techo \"initial\" >b &&\n> +\techo \"initial\" >c &&\n> +\tgit add a b c &&\n> +\tgit commit -m \"initial commit\"\n> +'\n> +\n> +test_expect_success 'create feature branch' '\n> +\tgit checkout -b feature &&\n> +\techo \"modified\" >b &&\n> +\techo \"modified\" >c &&\n> +\tgit add b c &&\n> +\tgit commit -m \"modification\"\n> +'\n> +\n> +test_expect_success 'perform sparse checkout of master' '\n> +\tgit config --local --bool core.sparsecheckout true &&\n> +\techo \"!/*\" >.git/info/sparse-checkout &&\n> +\techo \"/a\" >>.git/info/sparse-checkout &&\n> +\techo \"/c\" >>.git/info/sparse-checkout &&\n> +\tgit checkout master &&\n> +\ttest_path_is_file a &&\n> +\ttest_path_is_missing b &&\n> +\ttest_path_is_file c\n> +'\n> +\n> +test_expect_success 'merge feature branch into sparse checkout of master' '\n> +\tgit merge feature &&\n> +\ttest_path_is_file a &&\n> +\ttest_path_is_missing b &&\n> +\ttest_path_is_file c &&\n> +\ttest \"$(cat c)\" = \"modified\"\n> +'\n> +\n> +test_expect_success 'return to full checkout of master' '\n> +\tgit checkout feature &&\n> +\techo \"/*\" >.git/info/sparse-checkout &&\n> +\tgit checkout master &&\n> +\ttest_path_is_file a &&\n> +\ttest_path_is_file b &&\n> +\ttest_path_is_file c &&\n> +\ttest \"$(cat b)\" = \"modified\"\n> +'\n> +\n> +test_done\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 2927660..11a5300 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -223,7 +223,7 @@ static int check_updates(struct unpack_trees_options *o)\n>  \tfor (i = 0; i < index->cache_nr; i++) {\n>  \t\tstruct cache_entry *ce = index->cache[i];\n>  \n> -\t\tif (ce->ce_flags & CE_UPDATE) {\n> +\t\tif (ce->ce_flags & CE_UPDATE && !(ce->ce_flags & CE_WT_REMOVE)) {\n>  \t\t\tdisplay_progress(progress, ++cnt);\n>  \t\t\tce->ce_flags &= ~CE_UPDATE;\n>  \t\t\tif (o->update && !o->dry_run) {\n"},{"id":"266323","messageId":"20150718083719.GA19676@lanh","threadId":"39878","inReplyTo":"1437167967-5933-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-18T08:37:19Z","receivedAt":"2015-07-18T08:37:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jul 17, 2015 at 05:19:27PM -0400, David Turner wrote:\n> Don't update files in the worktree from cache entries which are\n> flagged with CE_WT_REMOVE.\n> \n> When a user does a sparse checkout, git removes files that are marked\n> with CE_WT_REMOVE (because they are out-of-scope for the sparse\n> checkout). If those files are also marked CE_UPDATE (for instance,\n> because they differ in the branch that is being checked out and the\n> outgoing branch), git would previously recreate them.  This patch\n> prevents them from being recreated.\n> \n> These erroneously-created files would also interfere with merges,\n> causing pre-merge revisions of out-of-scope files to appear in the\n> worktree.\n\nThank you both for catching this. Just a small suggestion. Perhaps we\nshould do this instead. apply_sparse_checkout() is the function where\nall \"action\" manipulation (add, delete, update files..) for sparse\ncheckout occurs and it should not ask to delete and update both at the\nsame time.\n\n-- 8< --\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 2927660..d6cf849 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -224,6 +224,9 @@ static int check_updates(struct unpack_trees_options *o)\n \t\tstruct cache_entry *ce = index->cache[i];\n \n \t\tif (ce->ce_flags & CE_UPDATE) {\n+\t\t\tif (ce->ce_flags & CE_WT_REMOVE)\n+\t\t\t\tdie(\"BUG: both update and delete flags are set on %s\",\n+\t\t\t\t    ce->name);\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tce->ce_flags &= ~CE_UPDATE;\n \t\t\tif (o->update && !o->dry_run) {\n@@ -293,6 +296,7 @@ static int apply_sparse_checkout(struct index_state *istate,\n \t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))\n \t\t\treturn -1;\n \t\tce->ce_flags |= CE_WT_REMOVE;\n+\t\tce->ce_flags &= ~CE_UPDATE;\n \t}\n \tif (was_skip_worktree && !ce_skip_worktree(ce)) {\n \t\tif (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))\n-- 8< --\n\n--\nDuy\n"},{"id":"266344","messageId":"xmqqpp3pyxh0.fsf@gitster.dls.corp.google.com","threadId":"39878","inReplyTo":"20150718083719.GA19676@lanh","subject":"Re: [PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-18T21:20:11Z","receivedAt":"2015-07-18T21:20:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> Thank you both for catching this. Just a small suggestion. Perhaps we\n> should do this instead. apply_sparse_checkout() is the function where\n> all \"action\" manipulation (add, delete, update files..) for sparse\n> checkout occurs and it should not ask to delete and update both at the\n> same time.\n\nSounds good.  The first hunk may merely be a noise, but the second\none is the true bugfix for the issue observed, I think.\n\n>\n> -- 8< --\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 2927660..d6cf849 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -224,6 +224,9 @@ static int check_updates(struct unpack_trees_options *o)\n>  \t\tstruct cache_entry *ce = index->cache[i];\n>  \n>  \t\tif (ce->ce_flags & CE_UPDATE) {\n> +\t\t\tif (ce->ce_flags & CE_WT_REMOVE)\n> +\t\t\t\tdie(\"BUG: both update and delete flags are set on %s\",\n> +\t\t\t\t    ce->name);\n>  \t\t\tdisplay_progress(progress, ++cnt);\n>  \t\t\tce->ce_flags &= ~CE_UPDATE;\n>  \t\t\tif (o->update && !o->dry_run) {\n> @@ -293,6 +296,7 @@ static int apply_sparse_checkout(struct index_state *istate,\n>  \t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))\n>  \t\t\treturn -1;\n>  \t\tce->ce_flags |= CE_WT_REMOVE;\n> +\t\tce->ce_flags &= ~CE_UPDATE;\n>  \t}\n>  \tif (was_skip_worktree && !ce_skip_worktree(ce)) {\n>  \t\tif (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))\n> -- 8< --\n>\n> --\n> Duy\n"},{"id":"266499","messageId":"1437414048.30911.10.camel@twopensource.com","threadId":"39878","inReplyTo":"20150718083719.GA19676@lanh","subject":"Re: [PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-07-20T17:40:48Z","receivedAt":"2015-07-20T17:40:48Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Anatole tells me that this works for us.  Thanks.\n\nOn Sat, 2015-07-18 at 15:37 +0700, Duy Nguyen wrote:\n> On Fri, Jul 17, 2015 at 05:19:27PM -0400, David Turner wrote:\n> > Don't update files in the worktree from cache entries which are\n> > flagged with CE_WT_REMOVE.\n> > \n> > When a user does a sparse checkout, git removes files that are marked\n> > with CE_WT_REMOVE (because they are out-of-scope for the sparse\n> > checkout). If those files are also marked CE_UPDATE (for instance,\n> > because they differ in the branch that is being checked out and the\n> > outgoing branch), git would previously recreate them.  This patch\n> > prevents them from being recreated.\n> > \n> > These erroneously-created files would also interfere with merges,\n> > causing pre-merge revisions of out-of-scope files to appear in the\n> > worktree.\n> \n> Thank you both for catching this. Just a small suggestion. Perhaps we\n> should do this instead. apply_sparse_checkout() is the function where\n> all \"action\" manipulation (add, delete, update files..) for sparse\n> checkout occurs and it should not ask to delete and update both at the\n> same time.\n> \n> -- 8< --\n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index 2927660..d6cf849 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -224,6 +224,9 @@ static int check_updates(struct unpack_trees_options *o)\n>  \t\tstruct cache_entry *ce = index->cache[i];\n>  \n>  \t\tif (ce->ce_flags & CE_UPDATE) {\n> +\t\t\tif (ce->ce_flags & CE_WT_REMOVE)\n> +\t\t\t\tdie(\"BUG: both update and delete flags are set on %s\",\n> +\t\t\t\t    ce->name);\n>  \t\t\tdisplay_progress(progress, ++cnt);\n>  \t\t\tce->ce_flags &= ~CE_UPDATE;\n>  \t\t\tif (o->update && !o->dry_run) {\n> @@ -293,6 +296,7 @@ static int apply_sparse_checkout(struct index_state *istate,\n>  \t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))\n>  \t\t\treturn -1;\n>  \t\tce->ce_flags |= CE_WT_REMOVE;\n> +\t\tce->ce_flags &= ~CE_UPDATE;\n>  \t}\n>  \tif (was_skip_worktree && !ce_skip_worktree(ce)) {\n>  \t\tif (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))\n> -- 8< --\n> \n> --\n> Duy\n"},{"id":"266582","messageId":"xmqqlhe9ters.fsf@gitster.dls.corp.google.com","threadId":"39878","inReplyTo":"xmqqpp3pyxh0.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2] unpack-trees: don't update files with CE_WT_REMOVE set","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-21T20:52:07Z","receivedAt":"2015-07-21T20:52:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> Thank you both for catching this. Just a small suggestion. Perhaps we\n>> should do this instead. apply_sparse_checkout() is the function where\n>> all \"action\" manipulation (add, delete, update files..) for sparse\n>> checkout occurs and it should not ask to delete and update both at the\n>> same time.\n>\n> Sounds good.  The first hunk may merely be a noise, but the second\n> one is the true bugfix for the issue observed, I think.\n\nI've replaced as/sparse-checkout-removal with the following.\n\nThanks, all.\n\n-- >8 --\nFrom: David Turner <dturner@twopensource.com>\nDate: Fri, 17 Jul 2015 17:19:27 -0400\nSubject: [PATCH] unpack-trees: don't update files with CE_WT_REMOVE set\n\nDon't update files in the worktree from cache entries which are\nflagged with CE_WT_REMOVE.\n\nWhen a user does a sparse checkout, git removes files that are\nmarked with CE_WT_REMOVE (because they are out-of-scope for the\nsparse checkout). If those files are also marked CE_UPDATE (for\ninstance, because they differ in the branch that is being checked\nout and the outgoing branch), git would previously recreate them.\nThis patch prevents them from being recreated.\n\nThese erroneously-created files would also interfere with merges,\ncausing pre-merge revisions of out-of-scope files to appear in the\nworktree.\n\napply_sparse_checkout() is the function where all \"action\"\nmanipulation (add, delete, update files..) for sparse checkout\noccurs; it should not ask to delete and update both at the same\ntime.\n\nSigned-off-by: Anatole Shaw <git-devel@omni.poc.net>\nSigned-off-by: David Turner <dturner@twopensource.com>\nHelped-by: Duy Nguyen <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t1090-sparse-checkout-scope.sh | 52 ++++++++++++++++++++++++++++++++++++++++\n unpack-trees.c                   |  4 ++++\n 2 files changed, 56 insertions(+)\n create mode 100755 t/t1090-sparse-checkout-scope.sh\n\ndiff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh\nnew file mode 100755\nindex 0000000..1f61eb3\n--- /dev/null\n+++ b/t/t1090-sparse-checkout-scope.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='sparse checkout scope tests'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo \"initial\" >a &&\n+\techo \"initial\" >b &&\n+\techo \"initial\" >c &&\n+\tgit add a b c &&\n+\tgit commit -m \"initial commit\"\n+'\n+\n+test_expect_success 'create feature branch' '\n+\tgit checkout -b feature &&\n+\techo \"modified\" >b &&\n+\techo \"modified\" >c &&\n+\tgit add b c &&\n+\tgit commit -m \"modification\"\n+'\n+\n+test_expect_success 'perform sparse checkout of master' '\n+\tgit config --local --bool core.sparsecheckout true &&\n+\techo \"!/*\" >.git/info/sparse-checkout &&\n+\techo \"/a\" >>.git/info/sparse-checkout &&\n+\techo \"/c\" >>.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c\n+'\n+\n+test_expect_success 'merge feature branch into sparse checkout of master' '\n+\tgit merge feature &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_missing b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat c)\" = \"modified\"\n+'\n+\n+test_expect_success 'return to full checkout of master' '\n+\tgit checkout feature &&\n+\techo \"/*\" >.git/info/sparse-checkout &&\n+\tgit checkout master &&\n+\ttest_path_is_file a &&\n+\ttest_path_is_file b &&\n+\ttest_path_is_file c &&\n+\ttest \"$(cat b)\" = \"modified\"\n+'\n+\n+test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 02f69ae..f177c0e 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -227,6 +227,9 @@ static int check_updates(struct unpack_trees_options *o)\n \t\tstruct cache_entry *ce = index->cache[i];\n \n \t\tif (ce->ce_flags & CE_UPDATE) {\n+\t\t\tif (ce->ce_flags & CE_WT_REMOVE)\n+\t\t\t\tdie(\"BUG: both update and delete flags are set on %s\",\n+\t\t\t\t    ce->name);\n \t\t\tdisplay_progress(progress, ++cnt);\n \t\t\tce->ce_flags &= ~CE_UPDATE;\n \t\t\tif (o->update && !o->dry_run) {\n@@ -290,6 +293,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt\n \t\tif (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))\n \t\t\treturn -1;\n \t\tce->ce_flags |= CE_WT_REMOVE;\n+\t\tce->ce_flags &= ~CE_UPDATE;\n \t}\n \tif (was_skip_worktree && !ce_skip_worktree(ce)) {\n \t\tif (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))\n-- \n2.5.0-rc2-392-g7dbe568\n"}]}