{"thread":{"id":"25496","subject":"pulling the root commit overwrites untracked files without warning (1.7.2.3)","startedAt":"2010-10-21T13:18:19Z","lastAt":"2010-11-15T01:51:06Z","messageCount":9,"participants":["Gert Palok","Clemens Buchacher","Miles Bader"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"153960","messageId":"AANLkTimDnyzyV1FEEwEuxLfG1nSOcNa7Hzwt7DDssjba@mail.gmail.com","threadId":"25496","inReplyTo":null,"subject":"pulling the root commit overwrites untracked files without warning (1.7.2.3)","fromName":"Gert Palok","fromEmail":"gert@planc.ee","sentAt":"2010-10-21T13:18:19Z","receivedAt":"2010-10-21T13:18:19Z","isPatch":false,"sender":{"key":"gert@planc.ee","avatar":null},"body":"Hi\n\nOn 1.7.2.3, pulling the root commit overwrites untracked files\n\nMinimal working example:\n$ git init wc1\n$ cd wc1\n$ echo a > a\n$ git add a\n$ git commit -m \"added a\"\n$ mkdir ../wc2\n$ cd ../wc2\n$ echo b > a\n$ git init\n$ git remote add origin ../wc1\n$ git pull origin master\n$ # expected: error: Untracked working tree file 'a' would be\noverwritten by merge.  Aborting\n$ # actual: no error\n$ cat a\n$ # expected: b\n$ # actual: a\n\nAn excerpt from the session:\ngert@planc ~/test/wc2 git[master?]\n768$ git pull origin master\nremote: Counting objects: 3, done.\nremote: Total 3 (delta 0), reused 0 (delta 0)\nUnpacking objects: 100% (3/3), done.\nFrom ../wc1\n * branch            master     -> FETCH_HEAD\ngert@planc ~/test/wc2 git[master]\n769$ cat a\na\n\n-- \nGert Palok\n"},{"id":"154207","messageId":"20101022211400.GA1774@localhost","threadId":"25496","inReplyTo":"AANLkTimDnyzyV1FEEwEuxLfG1nSOcNa7Hzwt7DDssjba@mail.gmail.com","subject":"Re: pulling the root commit overwrites untracked files without warning (1.7.2.3)","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-10-22T21:14:00Z","receivedAt":"2010-10-22T21:14:00Z","isPatch":false,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"Hi,\n\nOn Thu, Oct 21, 2010 at 04:18:19PM +0300, Gert Palok wrote:\n> \n> On 1.7.2.3, pulling the root commit overwrites untracked files\n\nThanks. This is probably fixed by the following series.\n\n http://mid.gmane.org/1286632380-7002-1-git-send-email-drizzd@aon.at\n\nI hope to finish it this weekend.\n\nClemens\n"},{"id":"154208","messageId":"20101022211709.GB1774@localhost","threadId":"25496","inReplyTo":"20101022211400.GA1774@localhost","subject":"Re: pulling the root commit overwrites untracked files without warning (1.7.2.3)","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-10-22T21:17:09Z","receivedAt":"2010-10-22T21:17:09Z","isPatch":false,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Fri, Oct 22, 2010 at 11:14:00PM +0200, Clemens Buchacher wrote:\n> Hi,\n> \n> On Thu, Oct 21, 2010 at 04:18:19PM +0300, Gert Palok wrote:\n> > \n> > On 1.7.2.3, pulling the root commit overwrites untracked files\n> \n> Thanks. This is probably fixed by the following series.\n> \n>  http://mid.gmane.org/1286632380-7002-1-git-send-email-drizzd@aon.at\n\nActually, it might not. But since it's related, I'll have a look at\nit.\n"},{"id":"155881","messageId":"20101114213453.GA29287@localhost","threadId":"25496","inReplyTo":"AANLkTimDnyzyV1FEEwEuxLfG1nSOcNa7Hzwt7DDssjba@mail.gmail.com","subject":"Re: pulling the root commit overwrites untracked files without warning (1.7.2.3)","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-11-14T21:34:53Z","receivedAt":"2010-11-14T21:34:53Z","isPatch":false,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"Hi,\n\nOn Thu, Oct 21, 2010 at 04:18:19PM +0300, Gert Palok wrote:\n> \n> On 1.7.2.3, pulling the root commit overwrites untracked files\n>\n> Minimal working example:                                                        \n> $ git init wc1                                                                  \n> $ cd wc1                                                                        \n> $ echo a > a                                                                    \n> $ git add a                                                                     \n> $ git commit -m \"added a\"                                                       \n> $ mkdir ../wc2                                                                  \n> $ cd ../wc2                                                                     \n> $ echo b > a                                                                    \n> $ git init                                                                      \n> $ git remote add origin ../wc1                                                  \n> $ git pull origin master                                                        \n> $ # expected: error: Untracked working tree file 'a' would be                   \n> overwritten by merge.  Aborting                                                 \n> $ # actual: no error                                                            \n> $ cat a                                                                         \n> $ # expected: b                                                                 \n> $ # actual: a\n\nI finally got a chance to look at this. Contrary to my initial\nsuspicion, it's not a problem with the merge algorithm at all. It\ndoesn't even do a merge.\n\nInstead, git merge finds that it has no valid HEAD and therefore\ndoes a hard reset, which obviously overwrites any files already\nthere.\n\nPatch to follow.\n\nClemens\n"},{"id":"155884","messageId":"20101114214601.GB29287@localhost","threadId":"25496","inReplyTo":"20101114213453.GA29287@localhost","subject":"[PATCH] do not overwrite untracked during merge from unborn branch","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-11-14T21:46:02Z","receivedAt":"2010-11-14T21:46:02Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"In case HEAD does not point to a valid commit yet, merge is\nimplemented as a hard reset. This will cause untracked files to be\noverwritten.\n\nInstead, assume the empty tree for HEAD and do a regular merge. An\nuntracked file will cause the merge to abort and do nothing. If no\nconflicting files are present, the merge will have the same effect\nas a hard reset.\n\nSigned-off-by: Clemens Buchacher <drizzd@aon.at>\n---\n\nThis is based on next and does not apply cleanly to master because\nof t7607. I can rebase it to master, but then it will conflict with\nnext later.\n\nClemens\n\n builtin/merge.c            |   20 +++++++++++++++++++-\n t/t7607-merge-overwrite.sh |   16 ++++++++++++++++\n 2 files changed, 35 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 10f091b..7571c93 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -234,6 +234,24 @@ static void save_state(void)\n \t\tdie(\"not a valid object: %s\", buffer.buf);\n }\n \n+static void read_empty(unsigned const char *sha1, int verbose)\n+{\n+\tint i = 0;\n+\tconst char *args[7];\n+\n+\targs[i++] = \"read-tree\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n+\targs[i++] = \"-m\";\n+\targs[i++] = \"-u\";\n+\targs[i++] = EMPTY_TREE_SHA1_HEX;\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"read-tree failed\");\n+}\n+\n static void reset_hard(unsigned const char *sha1, int verbose)\n {\n \tint i = 0;\n@@ -985,7 +1003,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"%s - not something we can merge\", argv[0]);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n \t\t\t\tDIE_ON_ERR);\n-\t\treset_hard(remote_head->sha1, 0);\n+\t\tread_empty(remote_head->sha1, 0);\n \t\treturn 0;\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\ndiff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh\nindex e49dd80..d4a499d 100755\n--- a/t/t7607-merge-overwrite.sh\n+++ b/t/t7607-merge-overwrite.sh\n@@ -127,4 +127,20 @@ test_expect_success SYMLINKS 'will not be confused by symlink in leading path' '\n \tgit checkout sub\n '\n \n+cat >expect <<\\EOF\n+error: Untracked working tree file 'c0.c' would be overwritten by merge.\n+fatal: read-tree failed\n+EOF\n+\n+test_expect_success 'will not overwrite untracked file on unborn branch' '\n+\tgit reset --hard c0 &&\n+\tgit rm -fr . &&\n+\tgit checkout --orphan new &&\n+\tcp important c0.c &&\n+\ttest_must_fail git merge c0 2>out &&\n+\ttest_cmp out expect &&\n+\ttest_path_is_missing .git/MERGE_HEAD &&\n+\ttest_cmp important c0.c\n+'\n+\n test_done\n-- \n1.7.3.1.105.g84915\n\n"},{"id":"155886","messageId":"20101114214927.GA29579@localhost","threadId":"25496","inReplyTo":"20101114214601.GB29287@localhost","subject":"[PATCH w/o PGP] do not overwrite untracked during merge from unborn branch","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-11-14T21:49:27Z","receivedAt":"2010-11-14T21:49:27Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"In case HEAD does not point to a valid commit yet, merge is\nimplemented as a hard reset. This will cause untracked files to be\noverwritten.\n\nInstead, assume the empty tree for HEAD and do a regular merge. An\nuntracked file will cause the merge to abort and do nothing. If no\nconflicting files are present, the merge will have the same effect\nas a hard reset.\n\nSigned-off-by: Clemens Buchacher <drizzd@aon.at>\n---\n\nOn Sun, Nov 14, 2010 at 10:46:02PM +0100, Clemens Buchacher wrote:\n> --MfFXiAuoTsnnDAfZ\n> Content-Type: text/plain; charset=us-ascii\n> Content-Disposition: inline\n> Content-Transfer-Encoding: quoted-printable\n>\n> This is based on next and does not apply cleanly to master because\n> of t7607. I can rebase it to master, but then it will conflict with\n> next later.\n\nWithout signature this time. Oops.\n\nClemens\n\n builtin/merge.c            |   20 +++++++++++++++++++-\n t/t7607-merge-overwrite.sh |   16 ++++++++++++++++\n 2 files changed, 35 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 10f091b..7571c93 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -234,6 +234,24 @@ static void save_state(void)\n \t\tdie(\"not a valid object: %s\", buffer.buf);\n }\n \n+static void read_empty(unsigned const char *sha1, int verbose)\n+{\n+\tint i = 0;\n+\tconst char *args[6];\n+\n+\targs[i++] = \"read-tree\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n+\targs[i++] = \"-m\";\n+\targs[i++] = \"-u\";\n+\targs[i++] = EMPTY_TREE_SHA1_HEX;\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"read-tree failed\");\n+}\n+\n static void reset_hard(unsigned const char *sha1, int verbose)\n {\n \tint i = 0;\n@@ -985,7 +1003,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"%s - not something we can merge\", argv[0]);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n \t\t\t\tDIE_ON_ERR);\n-\t\treset_hard(remote_head->sha1, 0);\n+\t\tread_empty(remote_head->sha1, 0);\n \t\treturn 0;\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\ndiff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh\nindex e49dd80..d4a499d 100755\n--- a/t/t7607-merge-overwrite.sh\n+++ b/t/t7607-merge-overwrite.sh\n@@ -127,4 +127,20 @@ test_expect_success SYMLINKS 'will not be confused by symlink in leading path' '\n \tgit checkout sub\n '\n \n+cat >expect <<\\EOF\n+error: Untracked working tree file 'c0.c' would be overwritten by merge.\n+fatal: read-tree failed\n+EOF\n+\n+test_expect_success 'will not overwrite untracked file on unborn branch' '\n+\tgit reset --hard c0 &&\n+\tgit rm -fr . &&\n+\tgit checkout --orphan new &&\n+\tcp important c0.c &&\n+\ttest_must_fail git merge c0 2>out &&\n+\ttest_cmp out expect &&\n+\ttest_path_is_missing .git/MERGE_HEAD &&\n+\ttest_cmp important c0.c\n+'\n+\n test_done\n-- \n1.7.3.1.105.g84915\n"},{"id":"155887","messageId":"20101114215315.GB29579@localhost","threadId":"25496","inReplyTo":"20101114214927.GA29579@localhost","subject":"[PATCH v2] do not overwrite untracked during merge from unborn branch","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-11-14T21:53:15Z","receivedAt":"2010-11-14T21:53:15Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"In case HEAD does not point to a valid commit yet, merge is\nimplemented as a hard reset. This will cause untracked files to be\noverwritten.\n\nInstead, assume the empty tree for HEAD and do a regular merge. An\nuntracked file will cause the merge to abort and do nothing. If no\nconflicting files are present, the merge will have the same effect\nas a hard reset.\n\nSigned-off-by: Clemens Buchacher <drizzd@aon.at>\n---\n\nOn Sun, Nov 14, 2010 at 10:49:27PM +0100, Clemens Buchacher wrote:\n> On Sun, Nov 14, 2010 at 10:46:02PM +0100, Clemens Buchacher wrote:\n> > --MfFXiAuoTsnnDAfZ\n> > Content-Type: text/plain; charset=us-ascii\n> > Content-Disposition: inline\n> > Content-Transfer-Encoding: quoted-printable\n> >\n> > This is based on next and does not apply cleanly to master because\n> > of t7607. I can rebase it to master, but then it will conflict with\n> > next later.\n> \n> Without signature this time. Oops.\n\nWrong again! (With args[6] instead of args[7].)  I wonder how many\ntimes I can get it wrong.\n\nClemens\n\n builtin/merge.c            |   20 +++++++++++++++++++-\n t/t7607-merge-overwrite.sh |   16 ++++++++++++++++\n 2 files changed, 35 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 10f091b..613543e 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -234,6 +234,24 @@ static void save_state(void)\n \t\tdie(\"not a valid object: %s\", buffer.buf);\n }\n \n+static void read_empty(unsigned const char *sha1, int verbose)\n+{\n+\tint i = 0;\n+\tconst char *args[7];\n+\n+\targs[i++] = \"read-tree\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n+\targs[i++] = \"-m\";\n+\targs[i++] = \"-u\";\n+\targs[i++] = EMPTY_TREE_SHA1_HEX;\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"read-tree failed\");\n+}\n+\n static void reset_hard(unsigned const char *sha1, int verbose)\n {\n \tint i = 0;\n@@ -985,7 +1003,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"%s - not something we can merge\", argv[0]);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n \t\t\t\tDIE_ON_ERR);\n-\t\treset_hard(remote_head->sha1, 0);\n+\t\tread_empty(remote_head->sha1, 0);\n \t\treturn 0;\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\ndiff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh\nindex e49dd80..d4a499d 100755\n--- a/t/t7607-merge-overwrite.sh\n+++ b/t/t7607-merge-overwrite.sh\n@@ -127,4 +127,20 @@ test_expect_success SYMLINKS 'will not be confused by symlink in leading path' '\n \tgit checkout sub\n '\n \n+cat >expect <<\\EOF\n+error: Untracked working tree file 'c0.c' would be overwritten by merge.\n+fatal: read-tree failed\n+EOF\n+\n+test_expect_success 'will not overwrite untracked file on unborn branch' '\n+\tgit reset --hard c0 &&\n+\tgit rm -fr . &&\n+\tgit checkout --orphan new &&\n+\tcp important c0.c &&\n+\ttest_must_fail git merge c0 2>out &&\n+\ttest_cmp out expect &&\n+\ttest_path_is_missing .git/MERGE_HEAD &&\n+\ttest_cmp important c0.c\n+'\n+\n test_done\n-- \n1.7.3.1.105.g84915\n"},{"id":"155890","messageId":"20101114220749.GA29786@localhost","threadId":"25496","inReplyTo":"20101114214953.GB16413@burratino","subject":"[PATCH v3] do not overwrite untracked during merge from unborn branch","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-11-14T22:07:49Z","receivedAt":"2010-11-14T22:07:49Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"In case HEAD does not point to a valid commit yet, merge is\nimplemented as a hard reset. This will cause untracked files to be\noverwritten.\n\nInstead, assume the empty tree for HEAD and do a regular merge. An\nuntracked file will cause the merge to abort and do nothing. If no\nconflicting files are present, the merge will have the same effect\nas a hard reset.\n\nSigned-off-by: Clemens Buchacher <drizzd@aon.at>\n---\n\nOn Sun, Nov 14, 2010 at 03:49:53PM -0600, Jonathan Nieder wrote:\n>\n> Naturally, this is the sort of patch that would want to be\n> fast-tracked to master (or even maint) if it is in good shape.\n\nOk, no problem. This applies to master and maint.\n\nClemens\n\n builtin/merge.c            |   20 +++++++++++++++++++-\n t/t7607-merge-overwrite.sh |   16 ++++++++++++++++\n 2 files changed, 35 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 10f091b..613543e 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -234,6 +234,24 @@ static void save_state(void)\n \t\tdie(\"not a valid object: %s\", buffer.buf);\n }\n \n+static void read_empty(unsigned const char *sha1, int verbose)\n+{\n+\tint i = 0;\n+\tconst char *args[7];\n+\n+\targs[i++] = \"read-tree\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n+\targs[i++] = \"-m\";\n+\targs[i++] = \"-u\";\n+\targs[i++] = EMPTY_TREE_SHA1_HEX;\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"read-tree failed\");\n+}\n+\n static void reset_hard(unsigned const char *sha1, int verbose)\n {\n \tint i = 0;\n@@ -985,7 +1003,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"%s - not something we can merge\", argv[0]);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n \t\t\t\tDIE_ON_ERR);\n-\t\treset_hard(remote_head->sha1, 0);\n+\t\tread_empty(remote_head->sha1, 0);\n \t\treturn 0;\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\ndiff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh\nindex d82349a..3988900 100755\n--- a/t/t7607-merge-overwrite.sh\n+++ b/t/t7607-merge-overwrite.sh\n@@ -84,4 +84,20 @@ test_expect_success 'will not overwrite removed file with staged changes' '\n \ttest_cmp important c1.c\n '\n \n+cat >expect <<\\EOF\n+error: Untracked working tree file 'c0.c' would be overwritten by merge.\n+fatal: read-tree failed\n+EOF\n+\n+test_expect_success 'will not overwrite untracked file on unborn branch' '\n+\tgit reset --hard c0 &&\n+\tgit rm -fr . &&\n+\tgit checkout --orphan new &&\n+\tcp important c0.c &&\n+\ttest_must_fail git merge c0 2>out &&\n+\ttest_cmp out expect &&\n+\ttest_path_is_missing .git/MERGE_HEAD &&\n+\ttest_cmp important c0.c\n+'\n+\n test_done\n-- \n1.7.3.1.105.g84915\n"},{"id":"155905","messageId":"87r5enbbhx.fsf@catnip.gol.com","threadId":"25496","inReplyTo":"20101114215315.GB29579@localhost","subject":"Re: [PATCH v2] do not overwrite untracked during merge from unborn branch","fromName":"Miles Bader","fromEmail":"miles@gnu.org","sentAt":"2010-11-15T01:51:06Z","receivedAt":"2010-11-15T01:51:06Z","isPatch":true,"sender":{"key":"miles@gnu.org","avatar":"https://gravatar.com/avatar/01069b69593af7bff28e2f97afeb3644ae6fe2f5f56cb3a8cf34c5fb8c36efe5?d=mp&s=160"},"body":"Clemens Buchacher <drizzd@aon.at> writes:\n> Wrong again! (With args[6] instead of args[7].)  I wonder how many\n> times I can get it wrong.\n\nHmm, well the use of external processes to implement such seemingly\nbasic functionality doesn't exactly help with the argument checking...\n\n... and now that I look (though only briefly :), builtin/read-tree.c\nseems almost trivial -- with the bulk of the code devoted to argument\nparsing, error reporting, and handling different cases...!\n\nMaybe it would be better to just rewrite \"read_empty\" (and\n\"reset_hard\"?) in terms of the underlying functions read-tree.c uses?\n\n-Miles\n\n-- \n`Cars give people wonderful freedom and increase their opportunities.\n But they also destroy the environment, to an extent so drastic that\n they kill all social life' (from _A Pattern Language_)\n"}]}