{"thread":{"id":"15309","subject":"file deletion in index lost after checkout -b","startedAt":"2008-09-01T03:44:14Z","lastAt":"2008-09-09T02:06:11Z","messageCount":6,"participants":["Jing Xue","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"89359","messageId":"20080901034414.GR6619@jabba.hq.digizenstudio.com","threadId":"15309","inReplyTo":null,"subject":"file deletion in index lost after checkout -b","fromName":"Jing Xue","fromEmail":"jingxue@digizenstudio.com","sentAt":"2008-09-01T03:44:14Z","receivedAt":"2008-09-01T03:44:14Z","isPatch":false,"sender":{"key":"jingxue@digizenstudio.com","avatar":null},"body":"In Git 1.6.0 the following sequence:\n\n$ git init\n$ echo 'abcdefgh' >1.txt\n$ echo '12345678' >2.txt\n$ git add 1.txt 2.txt\n$ git commit -m 'init'\n$ git rm 2.txt\n$ echo 'qwertyuiop' >>1.txt\n$ git add 1.txt\n$ echo 'asdfghjkl;' >3.txt\n$ git add 3.txt\n$ git status\n$ git checkout -b foo\n$ git status\n\nproduces this output:\n\nInitialized empty Git repository in /home/jingxue/workspace/sandboxes/test.git/.git/\nCreated initial commit 918f3c6: init\n 2 files changed, 2 insertions(+), 0 deletions(-)\n create mode 100644 1.txt\n create mode 100644 2.txt\nrm '2.txt'\n# On branch master\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n#\n#       modified:   1.txt\n#       deleted:    2.txt\n#       new file:   3.txt\n#\nM       1.txt\nA       3.txt\nSwitched to a new branch \"foo\"\n# On branch foo\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n#\n#       modified:   1.txt\n#       new file:   3.txt\n#\n\nThe deletion of 2.txt appears lost during 'checkout -b foo', while the\nmodification and addition were both brought over. Is it a bug?\n\nCheers.\n-- \nJing Xue\n"},{"id":"89826","messageId":"7vljy7xgs5.fsf@gitster.siamese.dyndns.org","threadId":"15309","inReplyTo":"20080901034414.GR6619@jabba.hq.digizenstudio.com","subject":"Re: file deletion in index lost after checkout -b","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-05T06:12:26Z","receivedAt":"2008-09-05T06:12:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jing Xue <jingxue@digizenstudio.com> writes:\n\n[jc: please redirect an answer _meant for you_ off to the list with M-F-T header]\n\n> In Git 1.6.0 the following sequence:\n> ...\n> The deletion of 2.txt appears lost during 'checkout -b foo', while the\n> modification and addition were both brought over. Is it a bug?\n\nThis behaviour is unchanged since early June 2005.\n\n    http://thread.gmane.org/gmane.comp.version-control.git/4641/focus=4646\n\nThis is exactly the case marked as *0*, which both Linus and I said \"it\nfeels somewhat wrong but otherwise we cannot start from an empty index\".\n\nWe may want to do better this time around, though.\n"},{"id":"89913","messageId":"20080906171108.GA10924@jabba.hq.digizenstudio.com","threadId":"15309","inReplyTo":"7vljy7xgs5.fsf@gitster.siamese.dyndns.org","subject":"Re: file deletion in index lost after checkout -b","fromName":"Jing Xue","fromEmail":"jingxue@digizenstudio.com","sentAt":"2008-09-06T17:11:08Z","receivedAt":"2008-09-06T17:11:08Z","isPatch":false,"sender":{"key":"jingxue@digizenstudio.com","avatar":null},"body":"On Thu, Sep 04, 2008 at 11:12:26PM -0700, Junio C Hamano wrote:\n> [jc: please redirect an answer _meant for you_ off to the list with M-F-T header]\n\nI changed mutt to not use M-F-T with the git list at all. Hope this one\nturns out better.\n\n> > The deletion of 2.txt appears lost during 'checkout -b foo', while the\n> > modification and addition were both brought over. Is it a bug?\n> \n> This behaviour is unchanged since early June 2005.\n> \n>     http://thread.gmane.org/gmane.comp.version-control.git/4641/focus=4646\n> \n> This is exactly the case marked as *0*, which both Linus and I said \"it\n> feels somewhat wrong but otherwise we cannot start from an empty index\".\n> \n> We may want to do better this time around, though.\n\nI have since found out that:\n\n1. file deletions in the working directory but not in index would not be forgotten. That\nmakes \"file deletions in index\" case rather a corner one.\n\n2. \"checkout -b -m\" would do the right thing.\n\nCheers.\n-- \nJing\n"},{"id":"89916","messageId":"7vej3xrvqf.fsf@gitster.siamese.dyndns.org","threadId":"15309","inReplyTo":"20080906171108.GA10924@jabba.hq.digizenstudio.com","subject":"Re: file deletion in index lost after checkout -b","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-06T18:10:32Z","receivedAt":"2008-09-06T18:10:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jing Xue <jingxue@digizenstudio.com> writes:\n\n> On Thu, Sep 04, 2008 at 11:12:26PM -0700, Junio C Hamano wrote:\n>> [jc: please redirect an answer _meant for you_ off to the list with M-F-T header]\n>\n> I changed mutt to not use M-F-T with the git list at all. Hope this one\n> turns out better.\n\nThanks; I meant to say \"please do not redirect\", but you got what I wanted\nto say correctly.\n\n>> > The deletion of 2.txt appears lost during 'checkout -b foo', while the\n>> > modification and addition were both brought over. Is it a bug?\n>> \n>> This behaviour is unchanged since early June 2005.\n>> \n>>     http://thread.gmane.org/gmane.comp.version-control.git/4641/focus=4646\n>> \n>> This is exactly the case marked as *0*, which both Linus and I said \"it\n>> feels somewhat wrong but otherwise we cannot start from an empty index\".\n>> \n>> We may want to do better this time around, though.\n>\n> I have since found out that:\n>\n> 1. file deletions in the working directory but not in index would not be forgotten. That\n> makes \"file deletions in index\" case rather a corner one.\n>\n> 2. \"checkout -b -m\" would do the right thing.\n\nBoth correct.  1. does not involve case *0*; 2. does not do two-tree\nswitch but internally uses three-tree switch and uses different codepath.\n"},{"id":"90038","messageId":"7vprnfic7e.fsf_-_@gitster.siamese.dyndns.org","threadId":"15309","inReplyTo":"7vljy7xgs5.fsf@gitster.siamese.dyndns.org","subject":"Re* file deletion in index lost after checkout -b","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-08T02:49:25Z","receivedAt":"2008-09-08T02:49:25Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jing Xue <jingxue@digizenstudio.com> writes:\n> ...\n>> In Git 1.6.0 the following sequence:\n>> ...\n>> The deletion of 2.txt appears lost during 'checkout -b foo', while the\n>> modification and addition were both brought over. Is it a bug?\n>\n> This behaviour is unchanged since early June 2005.\n>\n>     http://thread.gmane.org/gmane.comp.version-control.git/4641/focus=4646\n>\n> This is exactly the case marked as *0*, which both Linus and I said \"it\n> feels somewhat wrong but otherwise we cannot start from an empty index\".\n>\n> We may want to do better this time around, though.\n\nTry this patch.\n\n Documentation/git-read-tree.txt |   11 ++++++++++-\n builtin-checkout.c              |    1 +\n builtin-read-tree.c             |    1 +\n unpack-trees.c                  |   11 ++++++++++-\n unpack-trees.h                  |    1 +\n 5 files changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git c/Documentation/git-read-tree.txt i/Documentation/git-read-tree.txt\nindex 6f4b9b0..24155ab 100644\n--- c/Documentation/git-read-tree.txt\n+++ i/Documentation/git-read-tree.txt\n@@ -160,7 +160,10 @@ Here are the \"carry forward\" rules:\n       0 nothing             nothing  nothing  (does not happen)\n       1 nothing             nothing  exists   use M\n       2 nothing             exists   nothing  remove path from index\n-      3 nothing             exists   exists   use M\n+      3 nothing             exists   exists,  use M if index is empty\n+\t\t\t\t     H == M   keep index otherwise\n+\t\t\t\t     exists   fail\n+\t\t\t\t     H != M\n \n         clean I==H  I==M\n        ------------------\n@@ -207,6 +210,12 @@ you picked it up via e-mail in a patch form), `git diff-index\n merge, but it would not show in `git diff-index --cached $M`\n output after two-tree merge.\n \n+Case #3 is slightly tricky and needs explanation.  The result from this\n+rule logically should be to remove the path if the user staged the removal\n+of the path and then swiching to a new branch.  That however will prevent\n+the initial checkout from happening, so the rule is modified to use M (new\n+tree) only when the contents of the index is empty.  Otherwise the removal\n+of the path is kept as long as $H and $M are the same.\n \n 3-Way Merge\n ~~~~~~~~~~~\ndiff --git c/builtin-checkout.c i/builtin-checkout.c\nindex efdb1e0..c73a815 100644\n--- c/builtin-checkout.c\n+++ i/builtin-checkout.c\n@@ -242,6 +242,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t\t}\n \n \t\t/* 2-way merge to the new branch */\n+\t\ttopts.index_was_empty = !active_nr;\n \t\ttopts.update = 1;\n \t\ttopts.merge = 1;\n \t\ttopts.gently = opts->merge;\ndiff --git c/builtin-read-tree.c i/builtin-read-tree.c\nindex dddc304..41ece57 100644\n--- c/builtin-read-tree.c\n+++ i/builtin-read-tree.c\n@@ -160,6 +160,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t\t\tdie(\"you need to resolve your current index first\");\n \t\t\tstage = 1;\n \t\t\topts.merge = 1;\n+\t\t\topts.index_was_empty = !active_nr;\n \t\t\tcontinue;\n \t\t}\n \ndiff --git c/unpack-trees.c i/unpack-trees.c\nindex ef21c62..43ff477 100644\n--- c/unpack-trees.c\n+++ i/unpack-trees.c\n@@ -941,8 +941,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)\n \t\t\treturn -1;\n \t\t}\n \t}\n-\telse if (newtree)\n+\telse if (newtree) {\n+\t\tif (oldtree && !o->index_was_empty) {\n+\t\t\t/*\n+\t\t\t * deletion of the path was staged;\n+\t\t\t */\n+\t\t\tif (same(oldtree, newtree))\n+\t\t\t\treturn 1;\n+\t\t\treturn reject_merge(oldtree, o);\n+\t\t}\n \t\treturn merged_entry(newtree, current, o);\n+\t}\n \treturn deleted_entry(oldtree, current, o);\n }\n \ndiff --git c/unpack-trees.h i/unpack-trees.h\nindex 94e5672..61d82ce 100644\n--- c/unpack-trees.h\n+++ i/unpack-trees.h\n@@ -26,6 +26,7 @@ struct unpack_trees_options {\n \t\t     verbose_update:1,\n \t\t     aggressive:1,\n \t\t     skip_unmerged:1,\n+\t\t     index_was_empty:1,\n \t\t     gently:1;\n \tconst char *prefix;\n \tint pos;\n"},{"id":"90162","messageId":"20080909020611.GD10924@jabba.hq.digizenstudio.com","threadId":"15309","inReplyTo":"7vprnfic7e.fsf_-_@gitster.siamese.dyndns.org","subject":"Re: Re* file deletion in index lost after checkout -b","fromName":"Jing Xue","fromEmail":"jingxue@mindportcorp.com","sentAt":"2008-09-09T02:06:11Z","receivedAt":"2008-09-09T02:06:11Z","isPatch":false,"sender":{"key":"jingxue@mindportcorp.com","avatar":null},"body":"On Sun, Sep 07, 2008 at 07:49:25PM -0700, Junio C Hamano wrote:\n> Try this patch.\n\nWorks well. It doesn't give the fatal warning from \"checkout -m\" either.\n\"make test\" shows it doesn't break any existing tests.\n\nThanks.\n-- \nJing\n"}]}