{"thread":{"id":"42674","subject":"[PATCH] pathspec: warn on empty strings as pathspec","startedAt":"2016-06-21T02:15:23Z","lastAt":"2016-06-21T05:14:23Z","messageCount":2,"participants":["Emily Xie","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"289720","messageId":"20160621021515.64964-1-emilyxxie@gmail.com","threadId":"42674","inReplyTo":null,"subject":"[PATCH] pathspec: warn on empty strings as pathspec","fromName":"Emily Xie","fromEmail":"emilyxxie@gmail.com","sentAt":"2016-06-21T02:15:15Z","receivedAt":"2016-06-21T02:15:23Z","isPatch":true,"sender":{"key":"emilyxxie@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5360525?v=4"},"body":"For any command that takes a pathspec, passing an empty string will\nexecute the command on all files in the current directory. This\nresults in unexpected behavior. For example, git add \"\" adds all\nfiles to staging, while git rm -rf \"\" recursively removes all files\nfrom the working tree and index. A two-step implemetation will\nprevent such cases.\n\nThis patch, as step one, invokes a warning whenever an empty\nstring is detected as a pathspec, introducing users to the upcoming\nchange. For step two, a follow-up patch several release cycles later\nwill remove the warnings and actually implement the change by\nthrowing an error instead.\n\nSigned-off-by: Emily Xie <emilyxxie@gmail.com>\nReported-by: David Turner <novalis@novalis.org>\nMentored-by: Michail Denchev <mdenchev@gmail.com>\nThanks-to: Sarah Sharp <sarah@thesharps.us> and James Sharp <jamey@minilop.net>\n---\n pathspec.c     | 6 +++++-\n t/t3600-rm.sh  | 6 +++++-\n t/t3700-add.sh | 4 ++++\n 3 files changed, 14 insertions(+), 2 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex c9e9b6c..79e370e 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -402,8 +402,12 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n \n \tn = 0;\n-\twhile (argv[n])\n+\twhile (argv[n]) {\n+\t\tif (*argv[n] == '\\0')\n+\t\t\twarning(_(\"empty strings are not valid pathspecs and will no longer \"\n+\t\t\t          \"be supported in upcoming releases\"));\n \t\tn++;\n+\t}\n \n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\ndiff --git a/t/t3600-rm.sh b/t/t3600-rm.sh\nindex d046d98..4503a14 100755\n--- a/t/t3600-rm.sh\n+++ b/t/t3600-rm.sh\n@@ -881,4 +881,8 @@ test_expect_success 'rm files with two different errors' '\n \ttest_i18ncmp expect actual\n '\n \n-test_done\n+test_expect_success 'rm empty string should invoke warning' '\n+\tgit rm -rf \"\" 2>&1 | grep \"warning: empty string\"\n+'\n+\n+test_done\n\\ No newline at end of file\ndiff --git a/t/t3700-add.sh b/t/t3700-add.sh\nindex f14a665..5dbe8c2 100755\n--- a/t/t3700-add.sh\n+++ b/t/t3700-add.sh\n@@ -207,6 +207,10 @@ test_expect_success POSIXPERM,SANITY 'git add should fail atomically upon an unr\n \t! ( git ls-files foo1 | grep foo1 )\n '\n \n+test_expect_success 'git add empty string should invoke warning' '\n+\tgit add \"\" 2>&1 | grep \"warning: empty string\"\n+'\n+\n rm -f foo2\n \n test_expect_success POSIXPERM,SANITY 'git add --ignore-errors' '\n-- \n2.8.4\n\n"},{"id":"289724","messageId":"xmqqd1nbrurr.fsf@gitster.mtv.corp.google.com","threadId":"42674","inReplyTo":"20160621021515.64964-1-emilyxxie@gmail.com","subject":"Re: [PATCH] pathspec: warn on empty strings as pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-21T05:11:20Z","receivedAt":"2016-06-21T05:14:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Xie <emilyxxie@gmail.com> writes:\n\n> For any command that takes a pathspec, passing an empty string will\n> execute the command on all files in the current directory.\n\nOK.\n\n> This\n> results in unexpected behavior.\n\nTechnically speaking, your expectation is what is wrong here.  An\nempty string as a pathspec matches all paths.\n\n> For example, git add \"\" adds all\n> files to staging, while git rm -rf \"\" recursively removes all files\n> from the working tree and index.\n\nThat is a logical consequence that an empty string is a pathspec\nthat matches everything.  If somebody wants to add everything in\ntheir current directory, they can say 'git add \"\"'.  If you do not\nwant to do so, don't say 'git add \"\"'.\n\nYou need to argue why these are bad things to convince those who are\nused to the current behaviour that it is OK to break them.\n\nHere is my attempt.\n\n\tAn pathspec that is an empty string has been interpreted to\n\tmatch any path, as pathspec match is a leading substring\n\tmatch that honours directory boundary.  Just like pathspec\n\t\"dir/\" (or \"dir\") matches \"dir/file\", \"\" matches \"file\".\n\n\tHowever, a carelessly-written script may result in an empty\n\tstring assigned to a variable (perhaps caused by a bug in\n\tit), and may end up passing an empty string to a Git command\n\tinvocation, i.e.\n\n        \tgit rm \"$path\"\n        \tgit add \"$path\"\n\t\t\n\twhich would affect all paths in the current directory.\n\n\tWe cannot simply reject an empty string given as a pathspec\n\tto prevent this kind of mistake.  Because there surely are\n\texisting scripts that take advantage of the fact that an\n\tempty string matches all paths, such a change will break\n\tscripts that legitimately have been using an empty string\n\tfor that purpose.\n\n\tInstead, we need two step approach.  The first step is to\n\tnotice that the caller used an empty string as a pathspec,\n\tgive a warning to (1) declare that the use of an empty\n\tstring as \"match all\" will become invalid and (2) ask them\n\tto use \".\" instead if they mean \"match all\".\n\n\tAfter some release cycles, we can remove the warning and\n\tturn an empty string used as a pathspec element as an error.\n\n\tThis patch is the first step.\n\n\n> A two-step implemetation will\n> prevent such cases.\n\nThere is some leap/gap in logic here.  \n\n> This patch, as step one, invokes a warning whenever an empty\n> string is detected as a pathspec, introducing users to the upcoming\n> change. For step two, a follow-up patch several release cycles later\n> will remove the warnings and actually implement the change by\n> throwing an error instead.\n\nThis paragraph is OK, but I think I ended up covering the whole\nthing in my attempt ;-).\n\n\n> Signed-off-by: Emily Xie <emilyxxie@gmail.com>\n> Reported-by: David Turner <novalis@novalis.org>\n> Mentored-by: Michail Denchev <mdenchev@gmail.com>\n> Thanks-to: Sarah Sharp <sarah@thesharps.us> and James Sharp <jamey@minilop.net>\n> ---\n>  pathspec.c     | 6 +++++-\n>  t/t3600-rm.sh  | 6 +++++-\n>  t/t3700-add.sh | 4 ++++\n>  3 files changed, 14 insertions(+), 2 deletions(-)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index c9e9b6c..79e370e 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -402,8 +402,12 @@ void parse_pathspec(struct pathspec *pathspec,\n>  \t}\n>  \n>  \tn = 0;\n> -\twhile (argv[n])\n> +\twhile (argv[n]) {\n> +\t\tif (*argv[n] == '\\0')\n> +\t\t\twarning(_(\"empty strings are not valid pathspecs and will no longer \"\n> +\t\t\t          \"be supported in upcoming releases\"));\n>  \t\tn++;\n\nThree issues:\n\n * if argv[1] and argv[2] are both emtpy, the user will see the same\n   message twice.  Is it intended?  Is it acceptable?\n\n * \"Empty strings are not valid pathspecs\" is just plain wrong.  It\n   has been valid, but the warning message notifies that we are\n   going to make it invalid what has been valid.\n\n * \"Will no longer be supported\" is just plain useless.  We are\n   notifying that we will turn what they have been using as a valid\n   feature invalid.  What needs to accompany that notification is\n   how to update their script that have been happily working, which\n   we are going to break with the future change, in a way that will\n   keep working, i.e. \"please use . instead if you meant to match\n   all\".\n\n\n> +test_expect_success 'rm empty string should invoke warning' '\n> +\tgit rm -rf \"\" 2>&1 | grep \"warning: empty string\"\n> +'\n\nAs your warning is in _(\"...\"), you would need test_i18grep here, I think.\n\n> +test_done\n> \\ No newline at end of file\n\nOops.\n"}]}