{"thread":{"id":"35031","subject":"[PATCH] git submodule foreach: Skip eval for more than one argument","startedAt":"2013-09-26T20:10:15Z","lastAt":"2014-03-04T16:04:03Z","messageCount":9,"participants":["Anders Kaseorg","Johan Herland","Matthijs Kooijman"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"228287","messageId":"alpine.DEB.2.00.1309261605330.20647@dr-wily.mit.edu","threadId":"35031","inReplyTo":null,"subject":"[PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Anders Kaseorg","fromEmail":"andersk@mit.edu","sentAt":"2013-09-26T20:10:15Z","receivedAt":"2013-09-26T20:10:15Z","isPatch":true,"sender":{"key":"andersk@mit.edu","avatar":"https://avatars.githubusercontent.com/u/26471?v=4"},"body":"‘eval \"$@\"’ created an extra layer of shell interpretation, which was\nprobably not expected by a user who passed multiple arguments to git\nsubmodule foreach:\n\n$ git grep \"'\"\n[searches for single quotes]\n$ git submodule foreach git grep \"'\"\nEntering '[submodule]'\n/usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string\nStopping at '[submodule]'; script returned non-zero status.\n\nTo fix this, if the user passed more than one argument, just execute\n\"$@\" directly instead of passing it to eval.\n\nSigned-off-by: Anders Kaseorg <andersk@mit.edu>\n---\n git-submodule.sh | 7 ++++++-\n 1 file changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c17bef1..3381864 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -545,7 +545,12 @@ cmd_foreach()\n \t\t\t\tsm_path=$(relative_path \"$sm_path\") &&\n \t\t\t\t# we make $path available to scripts ...\n \t\t\t\tpath=$sm_path &&\n-\t\t\t\teval \"$@\" &&\n+\t\t\t\tif [ $# -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\teval \"$1\"\n+\t\t\t\telse\n+\t\t\t\t\t\"$@\"\n+\t\t\t\tfi &&\n \t\t\t\tif test -n \"$recursive\"\n \t\t\t\tthen\n \t\t\t\t\tcmd_foreach \"--recursive\" \"$@\"\n-- \n1.8.4\n"},{"id":"228305","messageId":"CALKQrgfhUEE+E5KsAWbP_zj6tozk+V=qvNU1PX9Z73Vu8unTiQ@mail.gmail.com","threadId":"35031","inReplyTo":"alpine.DEB.2.00.1309261605330.20647@dr-wily.mit.edu","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-09-27T08:48:44Z","receivedAt":"2013-09-27T08:48:44Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Thu, Sep 26, 2013 at 10:10 PM, Anders Kaseorg <andersk@mit.edu> wrote:\n> ‘eval \"$@\"’ created an extra layer of shell interpretation, which was\n> probably not expected by a user who passed multiple arguments to git\n> submodule foreach:\n>\n> $ git grep \"'\"\n> [searches for single quotes]\n> $ git submodule foreach git grep \"'\"\n> Entering '[submodule]'\n> /usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string\n> Stopping at '[submodule]'; script returned non-zero status.\n>\n> To fix this, if the user passed more than one argument, just execute\n> \"$@\" directly instead of passing it to eval.\n>\n> Signed-off-by: Anders Kaseorg <andersk@mit.edu>\n\nThe change looks good, and the existing tests (in t7407) pass. :-)\n\nTwo comments, however:\n\n1. Please add the use case you mention above as a new test case, so\nthat we can easily catch future regressions.\n\n2. If we are unlucky there might be existing users that work around\nthe existing behavior by adding an extra level of quoting (i.e. doing\nthe equivalent of git submodule foreach git grep \"\\'\" in your example\nabove). Will their workaround break as a result of your change? Is\nthat acceptable?\n\n\nHave fun! :)\n\n...Johan\n\n> ---\n>  git-submodule.sh | 7 ++++++-\n>  1 file changed, 6 insertions(+), 1 deletion(-)\n>\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index c17bef1..3381864 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -545,7 +545,12 @@ cmd_foreach()\n>                                 sm_path=$(relative_path \"$sm_path\") &&\n>                                 # we make $path available to scripts ...\n>                                 path=$sm_path &&\n> -                               eval \"$@\" &&\n> +                               if [ $# -eq 1 ]\n> +                               then\n> +                                       eval \"$1\"\n> +                               else\n> +                                       \"$@\"\n> +                               fi &&\n>                                 if test -n \"$recursive\"\n>                                 then\n>                                         cmd_foreach \"--recursive\" \"$@\"\n> --\n> 1.8.4\n>\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"228309","messageId":"alpine.DEB.2.00.1309270606290.20647@dr-wily.mit.edu","threadId":"35031","inReplyTo":"CALKQrgfhUEE+E5KsAWbP_zj6tozk+V=qvNU1PX9Z73Vu8unTiQ@mail.gmail.com","subject":"[PATCH v2] git submodule foreach: Skip eval for more than one argument","fromName":"Anders Kaseorg","fromEmail":"andersk@mit.edu","sentAt":"2013-09-27T10:23:55Z","receivedAt":"2013-09-27T10:23:55Z","isPatch":true,"sender":{"key":"andersk@mit.edu","avatar":"https://avatars.githubusercontent.com/u/26471?v=4"},"body":"‘eval \"$@\"’ created an extra layer of shell interpretation, which was\nprobably not expected by a user who passed multiple arguments to git\nsubmodule foreach:\n\n$ git grep \"'\"\n[searches for single quotes]\n$ git submodule foreach git grep \"'\"\nEntering '[submodule]'\n/usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string\nStopping at '[submodule]'; script returned non-zero status.\n\nTo fix this, if the user passed more than one argument, just execute\n\"$@\" directly instead of passing it to eval.\n\nSigned-off-by: Anders Kaseorg <andersk@mit.edu>\n---\n\nOn Fri, 27 Sep 2013, Johan Herland wrote:\n> 1. Please add the use case you mention above as a new test case, so\n> that we can easily catch future regressions.\n\nTest added.\n\n> 2. If we are unlucky there might be existing users that work around the \n> existing behavior by adding an extra level of quoting (i.e. doing the \n> equivalent of git submodule foreach git grep \"\\'\" in your example \n> above). Will their workaround break as a result of your change? Is that \n> acceptable?\n\nAnyone adding an extra level of quoting ought to realize that they should \nbe passing a single argument to submodule foreach, so that the reason for \nthe extra quoting is clear:\n  git submodule foreach \"git grep \\'\"\nwill not break.  If someone is actually doing\n  git submodule foreach git grep \"\\'\"\nthen this will change in behavior.  I think this change is important.\n\n(One could even imagine someone feeding untrusted input to\n  git submodule foreach git grep \"$variable\"\nwhich, without my patch, results in a nonobvious shell code injection \nvulnerability.)\n\nI considered an alternative fix where the first argument is always \nshell-evaulated and any others are not (i.e. cmd=$1 && shift && eval \n\"$cmd \\\"\\$@\\\"\"), which is potentially more useful in case the command \nneeds to use $path.  But that may be too confusing, and this way has some \nprecedent (e.g. perl’s system()).\n\nAnders\n\n\n git-submodule.sh             | 7 ++++++-\n t/t7407-submodule-foreach.sh | 9 +++++++++\n 2 files changed, 15 insertions(+), 1 deletion(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c17bef1..3381864 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -545,7 +545,12 @@ cmd_foreach()\n \t\t\t\tsm_path=$(relative_path \"$sm_path\") &&\n \t\t\t\t# we make $path available to scripts ...\n \t\t\t\tpath=$sm_path &&\n-\t\t\t\teval \"$@\" &&\n+\t\t\t\tif [ $# -eq 1 ]\n+\t\t\t\tthen\n+\t\t\t\t\teval \"$1\"\n+\t\t\t\telse\n+\t\t\t\t\t\"$@\"\n+\t\t\t\tfi &&\n \t\t\t\tif test -n \"$recursive\"\n \t\t\t\tthen\n \t\t\t\t\tcmd_foreach \"--recursive\" \"$@\"\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex be93f10..6b2fd39 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -329,4 +329,13 @@ test_expect_success 'command passed to foreach --recursive retains notion of std\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'multi-argument command passed to foreach is not shell-evaluated twice' '\n+\t(\n+\t\tcd super &&\n+\t\tgit submodule foreach \"echo \\\\\\\"quoted\\\\\\\"\" > ../expected &&\n+\t\tgit submodule foreach echo \\\"quoted\\\" > ../actual\n+\t) &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n1.8.4\n"},{"id":"228310","messageId":"CALKQrgfT1ijSx7hmtFRE7=Wm1LCtVH4ceeSQfuFF7Qswa+wRpg@mail.gmail.com","threadId":"35031","inReplyTo":"alpine.DEB.2.00.1309270606290.20647@dr-wily.mit.edu","subject":"Re: [PATCH v2] git submodule foreach: Skip eval for more than one argument","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-09-27T10:47:35Z","receivedAt":"2013-09-27T10:47:35Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Fri, Sep 27, 2013 at 12:23 PM, Anders Kaseorg <andersk@mit.edu> wrote:\n> ‘eval \"$@\"’ created an extra layer of shell interpretation, which was\n> probably not expected by a user who passed multiple arguments to git\n> submodule foreach:\n>\n> $ git grep \"'\"\n> [searches for single quotes]\n> $ git submodule foreach git grep \"'\"\n> Entering '[submodule]'\n> /usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string\n> Stopping at '[submodule]'; script returned non-zero status.\n>\n> To fix this, if the user passed more than one argument, just execute\n> \"$@\" directly instead of passing it to eval.\n>\n> Signed-off-by: Anders Kaseorg <andersk@mit.edu>\n\nAcked-by: Johan Herland <johan@herland.net>\n\n> On Fri, 27 Sep 2013, Johan Herland wrote:\n>> 2. If we are unlucky there might be existing users that work around the\n>> existing behavior by adding an extra level of quoting (i.e. doing the\n>> equivalent of git submodule foreach git grep \"\\'\" in your example\n>> above). Will their workaround break as a result of your change? Is that\n>> acceptable?\n>\n> Anyone adding an extra level of quoting ought to realize that they should\n> be passing a single argument to submodule foreach, so that the reason for\n> the extra quoting is clear:\n>   git submodule foreach \"git grep \\'\"\n> will not break.  If someone is actually doing\n>   git submodule foreach git grep \"\\'\"\n> then this will change in behavior.  I think this change is important.\n>\n> (One could even imagine someone feeding untrusted input to\n>   git submodule foreach git grep \"$variable\"\n> which, without my patch, results in a nonobvious shell code injection\n> vulnerability.)\n>\n> I considered an alternative fix where the first argument is always\n> shell-evaulated and any others are not (i.e. cmd=$1 && shift && eval\n> \"$cmd \\\"\\$@\\\"\"), which is potentially more useful in case the command\n> needs to use $path.  But that may be too confusing, and this way has some\n> precedent (e.g. perl’s system()).\n\nOk. I have nothing to add.\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"235992","messageId":"20140304135106.GD11566@login.drsnuggles.stderr.nl","threadId":"35031","inReplyTo":"alpine.DEB.2.00.1309261605330.20647@dr-wily.mit.edu","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Matthijs Kooijman","fromEmail":"matthijs@stdin.nl","sentAt":"2014-03-04T13:51:06Z","receivedAt":"2014-03-04T13:51:06Z","isPatch":true,"sender":{"key":"matthijs@stdin.nl","avatar":"https://avatars.githubusercontent.com/u/194491?v=4"},"body":"Hey folks,\n\nOn Thu, Sep 26, 2013 at 04:10:15PM -0400, Anders Kaseorg wrote:\n> ‘eval \"$@\"’ created an extra layer of shell interpretation, which was\n> probably not expected by a user who passed multiple arguments to git\n> submodule foreach:\n\nIt seems this patch has broken the use of $name, $path, etc. inside the\ncommand ran by foreach (when it contains more than one argument):\n\n\nmatthijs@grubby:~/test$ git --version\ngit version 1.9.0\nmatthijs@grubby:~/test$ git submodule foreach echo '$name'\nEntering 'test'\n$name\n\nBut it works on the single-argument version:\n\nmatthijs@grubby:~/test$ git submodule foreach 'echo $name'\nEntering 'test'\ntest\n\nAnd it used to work in older versions:\n\nmatthijs@login:~/test$ git --version\ngit version 1.7.5.4\nmatthijs@login:~/test$ git submodule foreach 'echo $name'\nEntering 'test'\ntest\nmatthijs@login:~/test$ git submodule foreach echo '$name'\nEntering 'test'\ntest\n\n\nI'm not sure how to fix this exactly. Adding \"export\" for the variables in\ngit-submodule.sh seems obvious but doesn't seem to be a complete solution. This\nmakes the variables available in the environment of any commands called (so git\nsubmodule sh -c 'echo $name') works, but the git submodule foreach echo '$name'\nabove still doesn't work, since the \"$@\" used does not do any substitution, it\njust executes $@ as a commandline unmodified. Ideally, you would do variable\nsubstitution, but not word splitting, but I'm not sure how to do that. Also,\nyou'd still need one more layer of backslash escapes, which is probably what\nthis commit wanted to prevent...\n\nNote that saying \"you should use the single argument version if you need\nthose variables\" doesn't seem possible in all cases. In particular, I'm\ncreating an alias that calls git submodule foreach, where the alias\ncontains part of the command and the rest of command comes from\narguments to the alias, meaning we always have at least two arguments...\n\nFinally, the new behaviour (e.g., eval with one argument, directly\nexecute with multiple) is not documented in the manpage, but it seems\nrelevant enough to need documentation?\n\nGr.\n\nMatthijs\n\n> \n> $ git grep \"'\"\n> [searches for single quotes]\n> $ git submodule foreach git grep \"'\"\n> Entering '[submodule]'\n> /usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string\n> Stopping at '[submodule]'; script returned non-zero status.\n> \n> To fix this, if the user passed more than one argument, just execute\n> \"$@\" directly instead of passing it to eval.\n> \n> Signed-off-by: Anders Kaseorg <andersk@mit.edu>\n> ---\n>  git-submodule.sh | 7 ++++++-\n>  1 file changed, 6 insertions(+), 1 deletion(-)\n> \n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index c17bef1..3381864 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -545,7 +545,12 @@ cmd_foreach()\n>  \t\t\t\tsm_path=$(relative_path \"$sm_path\") &&\n>  \t\t\t\t# we make $path available to scripts ...\n>  \t\t\t\tpath=$sm_path &&\n> -\t\t\t\teval \"$@\" &&\n> +\t\t\t\tif [ $# -eq 1 ]\n> +\t\t\t\tthen\n> +\t\t\t\t\teval \"$1\"\n> +\t\t\t\telse\n> +\t\t\t\t\t\"$@\"\n> +\t\t\t\tfi &&\n>  \t\t\t\tif test -n \"$recursive\"\n>  \t\t\t\tthen\n>  \t\t\t\t\tcmd_foreach \"--recursive\" \"$@\"\n> -- \n> 1.8.4\n> \n> \n> \n"},{"id":"235995","messageId":"CALKQrgfC1Cf=ZnwhaDUz-2q=vLa0UbO4ONybvCPu7RiF+3sm3w@mail.gmail.com","threadId":"35031","inReplyTo":"20140304135106.GD11566@login.drsnuggles.stderr.nl","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-03-04T14:53:24Z","receivedAt":"2014-03-04T14:53:24Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Tue, Mar 4, 2014 at 2:51 PM, Matthijs Kooijman <matthijs@stdin.nl> wrote:\n> matthijs@grubby:~/test$ git submodule foreach echo '$name'\n> Entering 'test'\n> $name\n\njherland@beta ~/test$ echo '$name'\n$name\n\nWhat would you expect echo '$name' to do? What happens if you use\ndouble instead of single quotes?\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"235996","messageId":"20140304145703.GE11566@login.drsnuggles.stderr.nl","threadId":"35031","inReplyTo":"CALKQrgfC1Cf=ZnwhaDUz-2q=vLa0UbO4ONybvCPu7RiF+3sm3w@mail.gmail.com","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Matthijs Kooijman","fromEmail":"matthijs@stdin.nl","sentAt":"2014-03-04T14:57:03Z","receivedAt":"2014-03-04T14:57:03Z","isPatch":true,"sender":{"key":"matthijs@stdin.nl","avatar":"https://avatars.githubusercontent.com/u/194491?v=4"},"body":"On Tue, Mar 04, 2014 at 03:53:24PM +0100, Johan Herland wrote:\n> On Tue, Mar 4, 2014 at 2:51 PM, Matthijs Kooijman <matthijs@stdin.nl> wrote:\n> > matthijs@grubby:~/test$ git submodule foreach echo '$name'\n> > Entering 'test'\n> > $name\n> \n> jherland@beta ~/test$ echo '$name'\n> $name\n> \n> What would you expect echo '$name' to do?\nIf I run git submodule foreach each '$name', then my shell eats the\nsingle quotes (which are only to prevent my shell from interpreting\n$name). git submodule will see $name, so it will run echo $name, not\necho '$name'.\n\n> What happens if you use double instead of single quotes?\nThen my shell eats up the double quotes _and_ replaces $name with\nnothing, so I can't expect git submodule to replace it with the\nsubmodule name then :-)\n\nDoes that help to clarify what I mean?\n\nGr.\n\nMatthijs\n"},{"id":"235997","messageId":"CALKQrgcDZD=eDnK5ssqZ3bCpB2gvWPts2W22_ZsCq5UtCxtmhg@mail.gmail.com","threadId":"35031","inReplyTo":"20140304145703.GE11566@login.drsnuggles.stderr.nl","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2014-03-04T15:23:47Z","receivedAt":"2014-03-04T15:23:47Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Tue, Mar 4, 2014 at 3:57 PM, Matthijs Kooijman <matthijs@stdin.nl> wrote:\n> On Tue, Mar 04, 2014 at 03:53:24PM +0100, Johan Herland wrote:\n>> What would you expect echo '$name' to do?\n> If I run git submodule foreach each '$name', then my shell eats the\n> single quotes (which are only to prevent my shell from interpreting\n> $name). git submodule will see $name, so it will run echo $name, not\n> echo '$name'.\n>\n>> What happens if you use double instead of single quotes?\n> Then my shell eats up the double quotes _and_ replaces $name with\n> nothing, so I can't expect git submodule to replace it with the\n> submodule name then :-)\n>\n> Does that help to clarify what I mean?\n\nOk, so IINM, Anders' original commit was about making \"git submodule\nforeach <command>\" behave more like \"<command>\" (from a naive user's\nperspective), while you rather expect to insert quotes/escapes to\nfinely control exactly when shell interpretation happens. Aren't these\nPOVs mutually incompatible? Is the only 'real' solution to forbid\nmultitple arguments, and force everybody to quote the entire command?\n\nI don't particularly care which way it goes, as long as (a) the common\ncase behaves as most users would expect, (b) the uncommon/complicated\ncase is still _possible_ (though not necessarily simple), and (c) we\ndon't break a sizable number of existing users.\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"236004","messageId":"20140304160403.GF11566@login.drsnuggles.stderr.nl","threadId":"35031","inReplyTo":"CALKQrgcDZD=eDnK5ssqZ3bCpB2gvWPts2W22_ZsCq5UtCxtmhg@mail.gmail.com","subject":"Re: [PATCH] git submodule foreach: Skip eval for more than one argument","fromName":"Matthijs Kooijman","fromEmail":"matthijs@stdin.nl","sentAt":"2014-03-04T16:04:03Z","receivedAt":"2014-03-04T16:04:03Z","isPatch":true,"sender":{"key":"matthijs@stdin.nl","avatar":"https://avatars.githubusercontent.com/u/194491?v=4"},"body":"Hey Johan,\n\n> Ok, so IINM, Anders' original commit was about making \"git submodule\n> foreach <command>\" behave more like \"<command>\" (from a naive user's\n> perspective),\nOk, that makes sense.\n\n> while you rather expect to insert quotes/escapes to finely control\n> exactly when shell interpretation happens.\nWell, I mostly expect that the $name and $path that git submodule makes\navailable to each command invocation can actually be used by the\ncommand.\n\n> Aren't these POVs mutually incompatible? Is the only 'real' solution\n> to forbid multitple arguments, and force everybody to quote the entire\n> command?\nYes, I think you're right that they're mutually exclusive. Specifically,\nif you expect git submodule foreach <command> to behave like <command>,\nthat means you expect the (interactive) shell to do all the\ninterpolation, word-splitting, etc. If so, you can't then later still do\ninterpolation (of course, you could do sed magic to just replace $name\nand $path, etc., but that's broken).\n\n> I don't particularly care which way it goes, as long as (a) the common\n> case behaves as most users would expect, (b) the uncommon/complicated\n> case is still _possible_ (though not necessarily simple), and (c) we\n> don't break a sizable number of existing users.\nWell, if you call submodule directly, you can now just put everything in\na single command and get $name interpolation.\n\nAs I mentioned, I couldn't do this because I was using a git alias.\nHowever, a bit of fiddling showed a solution to that using a shell\nfunction:\n\n[alias]\n\teach = \"!f(){ git submodule foreach --quiet \\\"echo \\\\$name $*\\\";}; f\"\n\nThis uses a shell function to collect all alias arguments and then uses\n$* to expand them again into the single submodule foreach argument. Note\nthat $* is expanded when evaluating the alias, while \\\\$name is expanded\nlater inside submodule.\n\nThis suggests that with the current code, the more complicated cases are\nstill possible. There is one catch in this approach, in that the\noriginal word splitting is not preserved ($* expands to just the\nunquoted arguments as a single word). I'm not sure if this is fixable\n($@ expands to multiple quoted words, but then foreach sees multiple\narguments and doesn't do the eval). One would need to escape the output\nof $@ somehow (e.g., add \\ before \", but that would become terribly\ncomplicated I expect...).\n\n\nPerhaps an explicit --eval switch to git submodule makes sense for\ncomplete control? If it has a correspondning --no-eval, you can even\npass a single-argument command without evalling, while still keeping the\ncurrent \"least surprise\" approach as the default?\n\nWhatever behaviour is settled for, it should be documented in the\nsubmodule manpage (which I think is not the case now).\n\nGr.\n\nMatthijs\n"}]}