{"thread":{"id":"45122","subject":"[PATCH v4 0/7] stash: support pathspec argument","startedAt":"2017-02-12T21:54:27Z","lastAt":"2017-03-01T22:59:03Z","messageCount":61,"participants":["Thomas Gummerer","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":4,"patchTotal":7},"messages":[{"id":"311374","messageId":"20170212215420.16701-1-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"mailto:20170205202642.14216-1-t.gummerer@gmail.com","subject":"[PATCH v4 0/7] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:13Z","receivedAt":"2017-02-12T21:54:27Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Thanks Peff and Junio for the review of the last round.\n\nChanges since v3:\n\n- Instead of using ${1-...} to check for missing arguments and dying\n  show the usage for stash instead, being more consistent with how the\n  rest of stash behaves\n- Let push_stash handle the --help argument from save_stash as well,\n  passing it through directly.\n\n- Fix the tests to not pipe the output to something, and thereby\n  swallowing the error codes\n\n- Update the commit message in 4/7 to acknowledge that there is a\n  small regression between the two versions\n\n- Correctly detect when there are no changes, and only show the\n  message once\n- Fix the accidental deletion of untracked files when a pathspec is\n  used.  Also added test cases for that.\n- Add documentation for git stash push to the usage text\n- Respect the -q flag and the GIT_QUIET environment variable\n\n- This also adds two new patches, one using push_stash instead of\n  save_stash for git stash without any verb.  The other allows using a\n  pathspec in the verb-less option of git stash.\n\nInterdiff below:\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex be55e456fa..b0825f4aca 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,15 +13,15 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n-\t     [-- <paths>...]\n+\t     [-- <pathspec>...]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 46367d40aa..a184b1e274 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,8 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -33,8 +36,8 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n@@ -64,11 +67,13 @@ create_stash () {\n \t\tcase \"$1\" in\n \t\t-m|--message)\n \t\t\tshift\n-\t\t\tstash_msg=${1?\"-m needs an argument\"}\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=\"$1\"\n \t\t\tnew_style=t\n \t\t\t;;\n \t\t-u|--include-untracked)\n \t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n \t\t\tuntracked=\"$1\"\n \t\t\tnew_style=t\n \t\t\t;;\n@@ -104,14 +109,11 @@ create_stash () {\n \tif test -z \"$new_style\"\n \tthen\n \t\tstash_msg=\"$*\"\n-\t\twhile test $# != 0\n-\t\tdo\n-\t\t\tshift\n-\t\tdone\n+\t\tset --\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -270,7 +272,8 @@ push_stash () {\n \t\t\t;;\n \t\t-m|--message)\n \t\t\tshift\n-\t\t\tstash_msg=${1?\"-m needs an argument\"}\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n \t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n@@ -308,7 +311,7 @@ push_stash () {\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n@@ -325,9 +328,23 @@ push_stash () {\n \tthen\n \t\tif test $# != 0\n \t\tthen\n-\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset --\n-\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout HEAD --\n-\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force --\n+\t\t\tsaved_untracked=\n+\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tsaved_untracked=$(\n+\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n+\t\t\t\t\t    xargs -0 git stash create -u all --)\n+\t\t\tfi\n+\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n+\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n+\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n+\t\t\tfi\n+\t\t\tif test -n \"$saved_untracked\"\n+\t\t\tthen\n+\t\t\t\tgit stash pop -q $saved_untracked\n+\t\t\tfi\n \t\telse\n \t\t\tgit reset --hard ${GIT_QUIET:+-q}\n \t\tfi\n@@ -357,9 +374,6 @@ save_stash () {\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n-\t\t--help)\n-\t\t\tshow_help\n-\t\t\t;;\n \t\t--)\n \t\t\tshift\n \t\t\tbreak\n@@ -685,17 +699,18 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -746,7 +761,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 461fe46045..22ac75377b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n@@ -780,7 +778,7 @@ test_expect_success 'push -m shows right message' '\n \tgit add foo &&\n \tgit stash push -m \"test message\" &&\n \techo \"stash@{0}: On master: test message\" >expect &&\n-\tgit stash list | head -n 1 >actual &&\n+\tgit stash list -1 >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -789,7 +787,7 @@ test_expect_success 'create stores correct message' '\n \tgit add foo &&\n \tSTASH_ID=$(git stash create \"create test message\") &&\n \techo \"On master: create test message\" >expect &&\n-\tgit show --pretty=%s ${STASH_ID} | head -n1 >actual &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -798,7 +796,7 @@ test_expect_success 'create with multiple arguments for the message' '\n \tgit add foo &&\n \tSTASH_ID=$(git stash create test untracked) &&\n \techo \"On master: test untracked\" >expect &&\n-\tgit show --pretty=%s ${STASH_ID} | head -n1 >actual &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -807,7 +805,7 @@ test_expect_success 'new style stash create stores correct message' '\n \tgit add foo &&\n \tSTASH_ID=$(git stash create -m \"create test message new style\") &&\n \techo \"On master: create test message new style\" >expect &&\n-\tgit show --pretty=%s ${STASH_ID} | head -n1 >actual &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -839,18 +837,63 @@ test_expect_success 'stash with multiple filename arguments' '\n '\n \n test_expect_success 'stash with file including $IFS character' '\n-\t>\"foo\tbar\" &&\n+\t>\"foo bar\" &&\n \t>foo &&\n-\t>untracked &&\n+\t>bar &&\n \tgit add foo* &&\n-\tgit stash push -- foo* &&\n-\ttest_path_is_missing \"foo\tbar\" &&\n-\ttest_path_is_missing foo &&\n-\ttest_path_is_file untracked &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n \tgit stash pop &&\n-\ttest_path_is_file \"foo\tbar\" &&\n+\ttest_path_is_file \"foo bar\" &&\n \ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only onece' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push -p not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'untracked file is not removed when using pathspecs' '\n+\t>untracked &&\n+\tgit stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 9a98e31a3e..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -197,16 +197,16 @@ test_expect_success 'stash push --include-untracked with pathspec' '\n '\n \n test_expect_success 'stash push with $IFS character' '\n-\t>\"foo\tbar\" &&\n+\t>\"foo bar\" &&\n \t>foo &&\n \t>bar &&\n \tgit add foo* &&\n-\tgit stash push --include-untracked -- foo* &&\n-\ttest_path_is_missing \"foo\tbar\" &&\n-\ttest_path_is_missing foo &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n \ttest_path_is_file bar &&\n \tgit stash pop &&\n-\ttest_path_is_file \"foo\tbar\" &&\n+\ttest_path_is_file \"foo bar\" &&\n \ttest_path_is_file foo &&\n \ttest_path_is_file bar\n '\n\nThomas Gummerer (7):\n  Documentation/stash: remove mention of git reset --hard\n  stash: introduce push verb\n  stash: add test for the create command line arguments\n  stash: introduce new format create\n  stash: teach 'push' (and 'create') to honor pathspec\n  stash: use stash_push for no verb form\n  stash: allow pathspecs in the no verb form\n\n Documentation/git-stash.txt        |  21 ++++-\n git-stash.sh                       | 157 +++++++++++++++++++++++++++++++------\n t/t3903-stash.sh                   | 127 +++++++++++++++++++++++++++++-\n t/t3905-stash-include-untracked.sh |  26 ++++++\n 4 files changed, 302 insertions(+), 29 deletions(-)\n\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311375","messageId":"20170212215420.16701-2-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 1/7] Documentation/stash: remove mention of git reset --hard","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:14Z","receivedAt":"2017-02-12T21:54:30Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Don't mention git reset --hard in the documentation for git stash save.\nIt's an implementation detail that doesn't matter to the end user and\nthus shouldn't be exposed to them.  In addition it's not quite true for\ngit stash -p, and will not be true when a filename argument to limit the\nstash to a few files is introduced.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9cef06e6..2e9e344cd7 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -47,8 +47,9 @@ OPTIONS\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n \n-\tSave your local modifications to a new 'stash', and run `git reset\n-\t--hard` to revert them.  The <message> part is optional and gives\n+\tSave your local modifications to a new 'stash' and roll them\n+\tback to HEAD (in the working tree and in the index).\n+\tThe <message> part is optional and gives\n \tthe description along with the stashed state.  For quickly making\n \ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n \tonly <message> does not trigger this action to prevent a misspelled\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311376","messageId":"20170212215420.16701-3-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 2/7] stash: introduce push verb","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:15Z","receivedAt":"2017-02-12T21:54:33Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Introduce a new git stash push verb in addition to git stash save.  The\npush verb is used to transition from the current command line arguments\nto a more conventional way, in which the message is given as an argument\nto the -m option.\n\nThis allows us to have pathspecs at the end of the command line\narguments like other Git commands do, so that the user can say which\nsubset of paths to stash (and leave others behind).\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh     | 46 +++++++++++++++++++++++++++++++++++++++++++---\n t/t3903-stash.sh |  9 +++++++++\n 2 files changed, 52 insertions(+), 3 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..8365ebba2a 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -9,6 +9,8 @@ USAGE=\"list [<options>]\n    or: $dashless branch <branchname> [<stash>]\n    or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -189,10 +191,11 @@ store_stash () {\n \treturn $ret\n }\n \n-save_stash () {\n+push_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tstash_msg=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +219,11 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -251,8 +259,6 @@ save_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n-\tstash_msg=\"$*\"\n-\n \tgit update-index -q --refresh\n \tif no_changes\n \tthen\n@@ -291,6 +297,36 @@ save_stash () {\n \tfi\n }\n \n+save_stash () {\n+\tpush_options=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\t# pass all options through to push_stash\n+\t\t\tpush_options=\"$push_options $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tstash_msg=\"$*\"\n+\n+\tif test -z \"$stash_msg\"\n+\tthen\n+\t\tpush_stash $push_options\n+\telse\n+\t\tpush_stash $push_options -m \"$stash_msg\"\n+\tfi\n+}\n+\n have_stash () {\n \tgit rev-parse --verify --quiet $ref_stash >/dev/null\n }\n@@ -617,6 +653,10 @@ save)\n \tshift\n \tsave_stash \"$@\"\n \t;;\n+push)\n+\tshift\n+\tpush_stash \"$@\"\n+\t;;\n apply)\n \tshift\n \tapply_stash \"$@\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2de3e18ce6..3577115807 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,13 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'push -m shows right message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit stash push -m \"test message\" &&\n+\techo \"stash@{0}: On master: test message\" >expect &&\n+\tgit stash list -1 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311377","messageId":"20170212215420.16701-7-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 6/7] stash: use stash_push for no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:19Z","receivedAt":"2017-02-12T21:54:36Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have stash_push, which accepts pathspec arguments, use\nit instead of stash_save in git stash without any additional verbs.\n\nThis does introduce a small regression.  Previously we allowed\ngit stash -- -message, with a hyphen in front of the message.  However\ngit stash -- message without the hyphen was not allowed.  After this\nchange adding a message to the stash, with or without hyphen is no\nlonger allowed.\n\nWhile this now allows specifying a message with the -m flag, it also\ndisallows messages without a hyphen.  This is to prevent user errors,\nwhere a user tries to stash something with a message, but changes their\nmind, and now would like to apply a stash, but forgets to remove the -m\nflag.  E.g. git stash -m mes^H^H^Happly would result in a stash with the\nmessage apply, while the user might have intended to apply a previous\nstash.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nIf this kind of regression introduced here is not acceptable, I think\nwe could hide this change between some kind of config option, and\ntransition users over later after a warning period.\n\n Documentation/git-stash.txt |  8 ++++----\n git-stash.sh                | 16 ++++++++--------\n t/t3903-stash.sh            |  4 +---\n 3 files changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex f462f393b0..b0825f4aca 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,11 +13,11 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\ndiff --git a/git-stash.sh b/git-stash.sh\nindex db56cf2c66..769cee9fd8 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,11 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n-   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t      [-- <pathspec>...]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -699,7 +699,7 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n@@ -709,7 +709,7 @@ do\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -760,7 +760,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 8b372c35fb..d568799da9 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311378","messageId":"20170212215420.16701-6-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 5/7] stash: teach 'push' (and 'create') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:18Z","receivedAt":"2017-02-12T21:54:39Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"While working on a repository, it's often helpful to stash the changes\nof a single or multiple files, and leave others alone.  Unfortunately\ngit currently offers no such option.  git stash -p can be used to work\naround this, but it's often impractical when there are a lot of changes\nover multiple files.\n\nAllow 'git stash push' to take pathspec to specify which paths to stash.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt        | 11 ++++++\n git-stash.sh                       | 50 ++++++++++++++++++++------\n t/t3903-stash.sh                   | 72 ++++++++++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh | 26 ++++++++++++++\n 4 files changed, 148 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex a138ed6a24..f462f393b0 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -15,9 +15,13 @@ SYNOPSIS\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n+'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n+\t     [--] [<pathspec>...]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n+\t     [-- <pathspec>...]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\n@@ -47,6 +51,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\n@@ -56,6 +61,12 @@ save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tonly <message> does not trigger this action to prevent a misspelled\n \tsubcommand from making an unwanted stash.\n +\n+When pathspec is given to 'git stash push', the new stash records the\n+modified states only for the files that match the pathspec.  The index\n+entries and working tree files are then rolled back to the state in\n+HEAD only for these files, too, leaving files that do not match the\n+pathspec intact.\n++\n If the `--keep-index` option is used, all changes already added to the\n index are left intact.\n +\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 6d629fc43f..db56cf2c66 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -11,6 +11,7 @@ USAGE=\"list [<options>]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n    or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t      [-- <pathspec>...]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -35,15 +36,15 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n untracked_files () {\n \texcl_opt=--exclude-standard\n \ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt\n+\tgit ls-files -o -z $excl_opt -- \"$@\"\n }\n \n clear_stash () {\n@@ -76,6 +77,11 @@ create_stash () {\n \t\t\tuntracked=\"$1\"\n \t\t\tnew_style=t\n \t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tnew_style=t\n+\t\t\tbreak\n+\t\t\t;;\n \t\t*)\n \t\t\tif test -n \"$new_style\"\n \t\t\tthen\n@@ -103,10 +109,11 @@ create_stash () {\n \tif test -z \"$new_style\"\n \tthen\n \t\tstash_msg=\"$*\"\n+\t\tset --\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -138,7 +145,7 @@ create_stash () {\n \t\t# Untracked files are stored by themselves in a parentless commit, for\n \t\t# ease of unpacking later.\n \t\tu_commit=$(\n-\t\t\tuntracked_files | (\n+\t\t\tuntracked_files \"$@\" | (\n \t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\t\texport GIT_INDEX_FILE &&\n \t\t\t\trm -f \"$TMPindex\" &&\n@@ -161,7 +168,7 @@ create_stash () {\n \t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n \t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- >\"$TMP-stagenames\" &&\n+\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n \t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n \t\t\tgit write-tree &&\n \t\t\trm -f \"$TMPindex\"\n@@ -175,7 +182,7 @@ create_stash () {\n \n \t\t# find out what the user wants\n \t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- &&\n+\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -304,7 +311,7 @@ push_stash () {\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n@@ -312,18 +319,39 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tif test $# != 0\n+\t\tthen\n+\t\t\tsaved_untracked=\n+\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tsaved_untracked=$(\n+\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n+\t\t\t\t\t    xargs -0 git stash create -u all --)\n+\t\t\tfi\n+\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n+\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n+\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n+\t\t\tfi\n+\t\t\tif test -n \"$saved_untracked\"\n+\t\t\tthen\n+\t\t\t\tgit stash pop -q $saved_untracked\n+\t\t\tfi\n+\t\telse\n+\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tfi\n \t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n \t\tif test -n \"$untracked\"\n \t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION\n+\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 812d0f7a40..8b372c35fb 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -811,4 +811,76 @@ test_expect_success 'new style stash create stores correct message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'stash -- <filename> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with multiple filename arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only onece' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push -p not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'untracked file is not removed when using pathspecs' '\n+\t>untracked &&\n+\tgit stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n+\ttest_path_is_file untracked\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex f372fc8ca8..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '\n \ttest -s .gitignore\n '\n \n+test_expect_success 'stash push --include-untracked with pathspec' '\n+\t>foo &&\n+\t>bar &&\n+\tgit stash push --include-untracked -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file foo\n+'\n+\n+test_expect_success 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311379","messageId":"20170212215420.16701-5-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 4/7] stash: introduce new format create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:17Z","receivedAt":"2017-02-12T21:54:41Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"git stash create currently supports a positional argument for adding a\nmessage.  This is not quite in line with how git commands usually take\ncomments (using a -m flag).\n\nAdd a new syntax for adding a message to git stash create using a -m\nflag.  This is with the goal of deprecating the old style git stash\ncreate with positional arguments.\n\nThis also adds a -u argument, for untracked files.  This is already used\ninternally as another positional argument, but can now be used from the\ncommand line.\n\nThis introduces a slight regression, when git stash create -m works is\nused.  Before this change, it created a stash with the message\n\"-m works\", but now it creates a stash with the message \"-m\".\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  1 +\n git-stash.sh                | 52 +++++++++++++++++++++++++++++++++++++++++----\n t/t3903-stash.sh            |  9 ++++++++\n 3 files changed, 58 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9e344cd7..a138ed6a24 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n 'git stash' clear\n 'git stash' create [<message>]\n+'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8365ebba2a..6d629fc43f 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -58,8 +58,52 @@ clear_stash () {\n }\n \n create_stash () {\n-\tstash_msg=\"$1\"\n-\tuntracked=\"$2\"\n+\tstash_msg=\n+\tuntracked=\n+\tnew_style=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=\"$1\"\n+\t\t\tnew_style=t\n+\t\t\t;;\n+\t\t-u|--include-untracked)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tuntracked=\"$1\"\n+\t\t\tnew_style=t\n+\t\t\t;;\n+\t\t*)\n+\t\t\tif test -n \"$new_style\"\n+\t\t\tthen\n+\t\t\t\techo \"invalid argument\"\n+\t\t\t\toption=\"$1\"\n+\t\t\t\t# TRANSLATORS: $option is an invalid option, like\n+\t\t\t\t# `--blah-blah'. The 7 spaces at the beginning of the\n+\t\t\t\t# second line correspond to \"error: \". So you should line\n+\t\t\t\t# up the second line with however many characters the\n+\t\t\t\t# translation of \"error: \" takes in your language. E.g. in\n+\t\t\t\t# English this is:\n+\t\t\t\t#\n+\t\t\t\t#    $ git stash save --blah-blah 2>&1 | head -n 2\n+\t\t\t\t#    error: unknown option for 'stash save': --blah-blah\n+\t\t\t\t#           To provide a message, use git stash save -- '--blah-blah'\n+\t\t\t\teval_gettextln \"error: unknown option for 'stash create': \\$option\"\n+\t\t\t\tusage\n+\t\t\tfi\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tif test -z \"$new_style\"\n+\tthen\n+\t\tstash_msg=\"$*\"\n+\tfi\n \n \tgit update-index -q --refresh\n \tif no_changes\n@@ -268,7 +312,7 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash \"$stash_msg\" $untracked\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n@@ -667,7 +711,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$*\" && echo \"$w_commit\"\n+\tcreate_stash \"$@\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex ffe3549ea5..812d0f7a40 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -802,4 +802,13 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'new style stash create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create -m \"create test message new style\") &&\n+\techo \"On master: create test message new style\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311380","messageId":"20170212215420.16701-4-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 3/7] stash: add test for the create command line arguments","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:16Z","receivedAt":"2017-02-12T21:54:44Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently there is no test showing the expected behaviour of git stash\ncreate's command line arguments.  Add a test for that to show the\ncurrent expected behaviour and to make sure future refactorings don't\nbreak those expectations.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/t3903-stash.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 3577115807..ffe3549ea5 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -784,4 +784,22 @@ test_expect_success 'push -m shows right message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create \"create test message\") &&\n+\techo \"On master: create test message\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'create with multiple arguments for the message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create test untracked) &&\n+\techo \"On master: test untracked\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311381","messageId":"20170212215420.16701-8-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v4 7/7] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T21:54:20Z","receivedAt":"2017-02-12T21:54:47Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that stash_push is used in the no verb form of stash, allow\nspecifying the command line for this form as well.  Always use -- to\ndisambiguate pathspecs from other non-option arguments.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh     |  1 +\n t/t3903-stash.sh | 15 +++++++++++++++\n 2 files changed, 16 insertions(+)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 769cee9fd8..a184b1e274 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -704,6 +704,7 @@ seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex d568799da9..22ac75377b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -881,4 +881,19 @@ test_expect_success 'untracked files are left in place when -u is not given' '\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g86e6ecc671.dirty\n\n"},{"id":"311382","messageId":"20170212220722.GB652@hank","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"Re: [PATCH v4 0/7] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-12T22:07:22Z","receivedAt":"2017-02-12T22:07:02Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/12, Thomas Gummerer wrote:\n> Thanks Peff and Junio for the review of the last round.\n>\n\nSorry it seems like I messed up the In-Reply-To header.  Previous rounds were at:\nv1: http://public-inbox.org/git/20170121200804.19009-1-t.gummerer@gmail.com/\nv2: http://public-inbox.org/git/20170129201604.30445-1-t.gummerer@gmail.com/\nv3: http://public-inbox.org/git/20170205202642.14216-1-t.gummerer@gmail.com/\n"},{"id":"311587","messageId":"20170214214045.GG652@hank","threadId":"45122","inReplyTo":"vpqefz0ohub.fsf@anie.imag.fr","subject":"Re: [PATCH v4 4/7] stash: introduce new format create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-14T21:40:45Z","receivedAt":"2017-02-14T21:40:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/14, Matthieu Moy wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> >  create_stash () {\n> > -\tstash_msg=\"$1\"\n> > -\tuntracked=\"$2\"\n> > +\tstash_msg=\n> > +\tuntracked=\n> > +\tnew_style=\n> > +\twhile test $# != 0\n> > +\tdo\n> > +\t\tcase \"$1\" in\n> > +\t\t-m|--message)\n> > +\t\t\tshift\n> > +\t\t\ttest -z ${1+x} && usage\n> > +\t\t\tstash_msg=\"$1\"\n> > +\t\t\tnew_style=t\n> > +\t\t\t;;\n> > +\t\t-u|--include-untracked)\n> > +\t\t\tshift\n> > +\t\t\ttest -z ${1+x} && usage\n> > +\t\t\tuntracked=\"$1\"\n> > +\t\t\tnew_style=t\n> > +\t\t\t;;\n> > +\t\t*)\n> > +\t\t\tif test -n \"$new_style\"\n> > +\t\t\tthen\n> > +\t\t\t\techo \"invalid argument\"\n> > +\t\t\t\toption=\"$1\"\n> > +\t\t\t\t# TRANSLATORS: $option is an invalid option, like\n> > +\t\t\t\t# `--blah-blah'. The 7 spaces at the beginning of the\n> > +\t\t\t\t# second line correspond to \"error: \". So you should line\n> > +\t\t\t\t# up the second line with however many characters the\n> > +\t\t\t\t# translation of \"error: \" takes in your language. E.g. in\n> > +\t\t\t\t# English this is:\n> > +\t\t\t\t#\n> > +\t\t\t\t#    $ git stash save --blah-blah 2>&1 | head -n 2\n> > +\t\t\t\t#    error: unknown option for 'stash save': --blah-blah\n> > +\t\t\t\t#           To provide a message, use git stash save -- '--blah-blah'\n> > +\t\t\t\teval_gettextln \"error: unknown option for 'stash create': \\$option\"\n> \n> The TRANSLATORS: hint seems a typoed cut-and-paste from somewhere else.\n> There are no 7 spaces in this message.\n> \n> Actually, if I read the code correctly, $option is not even necessarily\n> an option as you're matching *. Perhaps you meant something like\n> \n> \t-*)\n> \t\toption=\"$1\"\n> \t\t# TRANSLATORS: $option is an invalid option, like\n> \t\t# `--blah-blah'. The 7 spaces at the beginning of the\n> \t\t# second line correspond to \"error: \". So you should line\n> \t\t# up the second line with however many characters the\n> \t\t# translation of \"error: \" takes in your language. E.g. in\n> \t\t# English this is:\n> \t\t#\n> \t\t#    $ git stash save --blah-blah 2>&1 | head -n 2\n> \t\t#    error: unknown option for 'stash save': --blah-blah\n> \t\t#           To provide a message, use git stash save -- '--blah-blah'\n> \t\teval_gettextln \"error: unknown option for 'stash save': \\$option\n>        To provide a message, use git stash save -- '\\$option'\"\n>                 usage\n>                 ;;\n>         *)\n> \t\tif test -n \"$new_style\"\n> \t\tthen\n> \t        \targ=\"$1\"\n> \t        \teval_gettextln \"error: invalid argument for 'stash create': \\$arg\"\n> \t\t\tusage\n> \t\tfi\n>                 break\n> \t\t;;\n> \n> (untested)\n> \n> Also, you may want to guard against\n> \n>   git stash create \"some message\" -m \"some other message\"\n> \n> since you are already rejecting\n> \n>   git stash create -m \"some message\" \"some other message\"\n> \n> ? Or perhaps apply \"last one wins\" for both \"-m message\" and\n> \"message\"-without-dash-m.\n\nThanks, you're right I was missing some cases here.  As I just\nindicated in [1] however I think we can just make this an internal\ninterface, instead of user interface facing, so I think we'll need\nless error checking.\n\n> -- \n> Matthieu Moy\n> http://www-verimag.imag.fr/~moy/\n\n[1]: http://public-inbox.org/git/20170214213038.GE652@hank/\n"},{"id":"311958","messageId":"20170217224141.19183-1-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170212215420.16701-1-t.gummerer@gmail.com","subject":"[PATCH v5 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:35Z","receivedAt":"2017-02-17T22:41:12Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Thanks Matthieu, Peff and Junio for the discussion on v3 and v4.\n\nChanges since v4:\nDropped patch 1 from the series, as it's already in master\n\nInstead of changing the external interface to git stash create, only\nrefactor the internal create_stash() function to take -m and -u\narguments.  This also simplifies the internal option parsing.\n\nMake git stash -p an alias for git stash push -p, so git stash -p\n<pathspec> is allowed.\n\nInterdiff below:\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex b0825f4aca..97194576ef 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -53,9 +53,8 @@ OPTIONS\n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n-\tSave your local modifications to a new 'stash' and roll them\n-\tback to HEAD (in the working tree and in the index).\n-\tThe <message> part is optional and gives\n+\tSave your local modifications to a new 'stash', and run `git reset\n+\t--hard` to revert them.  The <message> part is optional and gives\n \tthe description along with the stashed state.  For quickly making\n \ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n \tonly <message> does not trigger this action to prevent a misspelled\ndiff --git a/git-stash.sh b/git-stash.sh\nindex a184b1e274..1446fbe2e8 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -67,51 +67,20 @@ create_stash () {\n \t\tcase \"$1\" in\n \t\t-m|--message)\n \t\t\tshift\n-\t\t\ttest -z ${1+x} && usage\n-\t\t\tstash_msg=\"$1\"\n-\t\t\tnew_style=t\n+\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n \t\t\t;;\n \t\t-u|--include-untracked)\n \t\t\tshift\n-\t\t\ttest -z ${1+x} && usage\n-\t\t\tuntracked=\"$1\"\n-\t\t\tnew_style=t\n+\t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n \t\t--)\n \t\t\tshift\n-\t\t\tnew_style=t\n-\t\t\tbreak\n-\t\t\t;;\n-\t\t*)\n-\t\t\tif test -n \"$new_style\"\n-\t\t\tthen\n-\t\t\t\techo \"invalid argument\"\n-\t\t\t\toption=\"$1\"\n-\t\t\t\t# TRANSLATORS: $option is an invalid option, like\n-\t\t\t\t# `--blah-blah'. The 7 spaces at the beginning of the\n-\t\t\t\t# second line correspond to \"error: \". So you should line\n-\t\t\t\t# up the second line with however many characters the\n-\t\t\t\t# translation of \"error: \" takes in your language. E.g. in\n-\t\t\t\t# English this is:\n-\t\t\t\t#\n-\t\t\t\t#    $ git stash save --blah-blah 2>&1 | head -n 2\n-\t\t\t\t#    error: unknown option for 'stash save': --blah-blah\n-\t\t\t\t#           To provide a message, use git stash save -- '--blah-blah'\n-\t\t\t\teval_gettextln \"error: unknown option for 'stash create': \\$option\"\n-\t\t\t\tusage\n-\t\t\tfi\n \t\t\tbreak\n \t\t\t;;\n \t\tesac\n \t\tshift\n \tdone\n \n-\tif test -z \"$new_style\"\n-\tthen\n-\t\tstash_msg=\"$*\"\n-\t\tset --\n-\tfi\n-\n \tgit update-index -q --refresh\n \tif no_changes \"$@\"\n \tthen\n@@ -698,6 +667,8 @@ apply_to_branch () {\n \t}\n }\n \n+test \"$1\" = \"-p\" && set \"push\" \"$@\"\n+\n PARSE_CACHE='--not-parsed'\n # The default command is \"push\" if nothing but options are given\n seen_non_option=\n@@ -740,7 +711,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$@\" && echo \"$w_commit\"\n+\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 22ac75377b..c0ae41e724 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -800,15 +800,6 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'new style stash create stores correct message' '\n-\t>foo &&\n-\tgit add foo &&\n-\tSTASH_ID=$(git stash create -m \"create test message new style\") &&\n-\techo \"On master: create test message new style\" >expect &&\n-\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'stash -- <filename> stashes and restores the file' '\n \t>foo &&\n \t>bar &&\n\nThomas Gummerer (6):\n  stash: introduce push verb\n  stash: add test for the create command line arguments\n  stash: refactor stash_create\n  stash: teach 'push' (and 'create_stash') to honor pathspec\n  stash: use stash_push for no verb form\n  stash: allow pathspecs in the no verb form\n\n Documentation/git-stash.txt        |  16 ++++-\n git-stash.sh                       | 128 ++++++++++++++++++++++++++++++-------\n t/t3903-stash.sh                   | 118 +++++++++++++++++++++++++++++++++-\n t/t3905-stash-include-untracked.sh |  26 ++++++++\n 4 files changed, 261 insertions(+), 27 deletions(-)\n\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311959","messageId":"20170217224141.19183-3-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 2/6] stash: add test for the create command line arguments","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:37Z","receivedAt":"2017-02-17T22:41:15Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently there is no test showing the expected behaviour of git stash\ncreate's command line arguments.  Add a test for that to show the\ncurrent expected behaviour and to make sure future refactorings don't\nbreak those expectations.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/t3903-stash.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 3577115807..ffe3549ea5 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -784,4 +784,22 @@ test_expect_success 'push -m shows right message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create \"create test message\") &&\n+\techo \"On master: create test message\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'create with multiple arguments for the message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create test untracked) &&\n+\techo \"On master: test untracked\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311960","messageId":"20170217224141.19183-5-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:39Z","receivedAt":"2017-02-17T22:41:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"While working on a repository, it's often helpful to stash the changes\nof a single or multiple files, and leave others alone.  Unfortunately\ngit currently offers no such option.  git stash -p can be used to work\naround this, but it's often impractical when there are a lot of changes\nover multiple files.\n\nAllow 'git stash push' to take pathspec to specify which paths to stash.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt        | 11 ++++++\n git-stash.sh                       | 48 +++++++++++++++++++------\n t/t3903-stash.sh                   | 72 ++++++++++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh | 26 ++++++++++++++\n 4 files changed, 146 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex d93c47446a..086c229db0 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -15,9 +15,13 @@ SYNOPSIS\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n+'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n+\t     [--] [<pathspec>...]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n+\t     [-- <pathspec>...]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\n@@ -47,6 +51,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n \tSave your local modifications to a new 'stash', and run `git reset\n \t--hard` to revert them.  The <message> part is optional and gives\n@@ -55,6 +60,12 @@ save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tonly <message> does not trigger this action to prevent a misspelled\n \tsubcommand from making an unwanted stash.\n +\n+When pathspec is given to 'git stash push', the new stash records the\n+modified states only for the files that match the pathspec.  The index\n+entries and working tree files are then rolled back to the state in\n+HEAD only for these files, too, leaving files that do not match the\n+pathspec intact.\n++\n If the `--keep-index` option is used, all changes already added to the\n index are left intact.\n +\ndiff --git a/git-stash.sh b/git-stash.sh\nindex e76741d37d..6b56f84d81 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -11,6 +11,7 @@ USAGE=\"list [<options>]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n    or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t      [-- <pathspec>...]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -35,15 +36,15 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n untracked_files () {\n \texcl_opt=--exclude-standard\n \ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt\n+\tgit ls-files -o -z $excl_opt -- \"$@\"\n }\n \n clear_stash () {\n@@ -72,12 +73,16 @@ create_stash () {\n \t\t\tshift\n \t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n \t\tesac\n \t\tshift\n \tdone\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -109,7 +114,7 @@ create_stash () {\n \t\t# Untracked files are stored by themselves in a parentless commit, for\n \t\t# ease of unpacking later.\n \t\tu_commit=$(\n-\t\t\tuntracked_files | (\n+\t\t\tuntracked_files \"$@\" | (\n \t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\t\texport GIT_INDEX_FILE &&\n \t\t\t\trm -f \"$TMPindex\" &&\n@@ -132,7 +137,7 @@ create_stash () {\n \t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n \t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- >\"$TMP-stagenames\" &&\n+\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n \t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n \t\t\tgit write-tree &&\n \t\t\trm -f \"$TMPindex\"\n@@ -146,7 +151,7 @@ create_stash () {\n \n \t\t# find out what the user wants\n \t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- &&\n+\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -275,7 +280,7 @@ push_stash () {\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n@@ -283,18 +288,39 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tif test $# != 0\n+\t\tthen\n+\t\t\tsaved_untracked=\n+\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tsaved_untracked=$(\n+\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n+\t\t\t\t\t    xargs -0 git stash create -u all --)\n+\t\t\tfi\n+\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n+\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n+\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n+\t\t\tfi\n+\t\t\tif test -n \"$saved_untracked\"\n+\t\t\tthen\n+\t\t\t\tgit stash pop -q $saved_untracked\n+\t\t\tfi\n+\t\telse\n+\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tfi\n \t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n \t\tif test -n \"$untracked\"\n \t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION\n+\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex ffe3549ea5..4fb800eec8 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -802,4 +802,76 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'stash -- <filename> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with multiple filename arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only onece' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push -p not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'untracked file is not removed when using pathspecs' '\n+\t>untracked &&\n+\tgit stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n+\ttest_path_is_file untracked\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex f372fc8ca8..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '\n \ttest -s .gitignore\n '\n \n+test_expect_success 'stash push --include-untracked with pathspec' '\n+\t>foo &&\n+\t>bar &&\n+\tgit stash push --include-untracked -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file foo\n+'\n+\n+test_expect_success 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311961","messageId":"20170217224141.19183-6-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 5/6] stash: use stash_push for no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:40Z","receivedAt":"2017-02-17T22:41:19Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have stash_push, which accepts pathspec arguments, use\nit instead of stash_save in git stash without any additional verbs.\n\nPreviously we allowed git stash -- -message, which is no longer allowed\nafter this patch.  Messages starting with a hyphen was allowed since\n3c2eb80f, (\"stash: simplify defaulting to \"save\" and reject unknown\noptions\").  However it was never the intent to allow that, but rather it\nwas allowed accidentally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  8 ++++----\n git-stash.sh                | 16 ++++++++--------\n t/t3903-stash.sh            |  4 +---\n 3 files changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 086c229db0..97194576ef 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,11 +13,11 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 6b56f84d81..2a33614cb7 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,11 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n-   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t      [-- <pathspec>...]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -668,7 +668,7 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n@@ -678,7 +678,7 @@ do\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -729,7 +729,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 4fb800eec8..7f90a247b4 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311962","messageId":"20170217224141.19183-7-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 6/6] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:41Z","receivedAt":"2017-02-17T22:41:23Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that stash_push is used in the no verb form of stash, allow\nspecifying the command line for this form as well.  Always use -- to\ndisambiguate pathspecs from other non-option arguments.\n\nAlso make git stash -p an alias for git stash push -p.  This allows\nusers to use git stash -p <pathspec>.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh     |  3 +++\n t/t3903-stash.sh | 15 +++++++++++++++\n 2 files changed, 18 insertions(+)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 2a33614cb7..1446fbe2e8 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -667,12 +667,15 @@ apply_to_branch () {\n \t}\n }\n \n+test \"$1\" = \"-p\" && set \"push\" \"$@\"\n+\n PARSE_CACHE='--not-parsed'\n # The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 7f90a247b4..c0ae41e724 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -872,4 +872,19 @@ test_expect_success 'untracked files are left in place when -u is not given' '\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311963","messageId":"20170217224141.19183-2-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 1/6] stash: introduce push verb","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:36Z","receivedAt":"2017-02-17T22:41:25Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Introduce a new git stash push verb in addition to git stash save.  The\npush verb is used to transition from the current command line arguments\nto a more conventional way, in which the message is given as an argument\nto the -m option.\n\nThis allows us to have pathspecs at the end of the command line\narguments like other Git commands do, so that the user can say which\nsubset of paths to stash (and leave others behind).\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh     | 46 +++++++++++++++++++++++++++++++++++++++++++---\n t/t3903-stash.sh |  9 +++++++++\n 2 files changed, 52 insertions(+), 3 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..8365ebba2a 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -9,6 +9,8 @@ USAGE=\"list [<options>]\n    or: $dashless branch <branchname> [<stash>]\n    or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -189,10 +191,11 @@ store_stash () {\n \treturn $ret\n }\n \n-save_stash () {\n+push_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tstash_msg=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +219,11 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -251,8 +259,6 @@ save_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n-\tstash_msg=\"$*\"\n-\n \tgit update-index -q --refresh\n \tif no_changes\n \tthen\n@@ -291,6 +297,36 @@ save_stash () {\n \tfi\n }\n \n+save_stash () {\n+\tpush_options=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\t# pass all options through to push_stash\n+\t\t\tpush_options=\"$push_options $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tstash_msg=\"$*\"\n+\n+\tif test -z \"$stash_msg\"\n+\tthen\n+\t\tpush_stash $push_options\n+\telse\n+\t\tpush_stash $push_options -m \"$stash_msg\"\n+\tfi\n+}\n+\n have_stash () {\n \tgit rev-parse --verify --quiet $ref_stash >/dev/null\n }\n@@ -617,6 +653,10 @@ save)\n \tshift\n \tsave_stash \"$@\"\n \t;;\n+push)\n+\tshift\n+\tpush_stash \"$@\"\n+\t;;\n apply)\n \tshift\n \tapply_stash \"$@\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2de3e18ce6..3577115807 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,13 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'push -m shows right message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit stash push -m \"test message\" &&\n+\techo \"stash@{0}: On master: test message\" >expect &&\n+\tgit stash list -1 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311964","messageId":"20170217224141.19183-4-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v5 3/6] stash: refactor stash_create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T22:41:38Z","receivedAt":"2017-02-17T22:41:27Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Refactor the internal stash_create function to use a -m flag for\nspecifying the message and -u flag to indicate whether untracked files\nshould be added to the stash.\n\nThis makes it easier to pass a pathspec argument to stash_create in the\nnext patch.\n\nThe user interface for git stash create stays the same.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  1 +\n git-stash.sh                | 23 +++++++++++++++++++----\n 2 files changed, 20 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9cef06e6..d93c47446a 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n 'git stash' clear\n 'git stash' create [<message>]\n+'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8365ebba2a..e76741d37d 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -58,8 +58,23 @@ clear_stash () {\n }\n \n create_stash () {\n-\tstash_msg=\"$1\"\n-\tuntracked=\"$2\"\n+\tstash_msg=\n+\tuntracked=\n+\tnew_style=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n+\t\t\t;;\n+\t\t-u|--include-untracked)\n+\t\t\tshift\n+\t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \n \tgit update-index -q --refresh\n \tif no_changes\n@@ -268,7 +283,7 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash \"$stash_msg\" $untracked\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n@@ -667,7 +682,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$*\" && echo \"$w_commit\"\n+\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\n-- \n2.11.0.301.g27b9849079.dirty\n\n"},{"id":"311968","messageId":"20170217230614.GH652@hank","threadId":"45122","inReplyTo":"xmqqr32wph97.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T23:06:14Z","receivedAt":"2017-02-17T23:05:43Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/17, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > Thanks Matthieu, Peff and Junio for the discussion on v3 and v4.\n> >\n> > Changes since v4:\n> > Dropped patch 1 from the series, as it's already in master\n> >\n> > Instead of changing the external interface to git stash create, only\n> > refactor the internal create_stash() function to take -m and -u\n> > arguments.  This also simplifies the internal option parsing.\n> \n> Yay.\n> \n> > Make git stash -p an alias for git stash push -p, so git stash -p\n> > <pathspec> is allowed.\n> \n> Nice.\n> \n> >\n> > Interdiff below:\n> >\n> > diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\n> > index b0825f4aca..97194576ef 100644\n> > --- a/Documentation/git-stash.txt\n> > +++ b/Documentation/git-stash.txt\n> > @@ -53,9 +53,8 @@ OPTIONS\n> >  save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n> >  push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n> >  \n> > -\tSave your local modifications to a new 'stash' and roll them\n> > -\tback to HEAD (in the working tree and in the index).\n> > -\tThe <message> part is optional and gives\n> > +\tSave your local modifications to a new 'stash', and run `git reset\n> > +\t--hard` to revert them.  The <message> part is optional and gives\n> >  \tthe description along with the stashed state.  For quickly making\n> >  \ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n> >  \tonly <message> does not trigger this action to prevent a misspelled\n> > diff --git a/git-stash.sh b/git-stash.sh\n> > index a184b1e274..1446fbe2e8 100755\n> > --- a/git-stash.sh\n> > +++ b/git-stash.sh\n> > @@ -67,51 +67,20 @@ create_stash () {\n> >  \t\tcase \"$1\" in\n> >  \t\t-m|--message)\n> >  \t\t\tshift\n> > -\t\t\ttest -z ${1+x} && usage\n> > -\t\t\tstash_msg=\"$1\"\n> > -\t\t\tnew_style=t\n> > +\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n> \n> Hmph, did you mean ${1?\"BUG: ...\"}?  The same for the one in \"-u\".\n\nAh yes sorry, you're right course.  Thanks.\n"},{"id":"311971","messageId":"xmqqfujcpgky.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"Re: [PATCH v5 0/6] stash: support pathspec argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-17T23:01:33Z","receivedAt":"2017-02-17T23:09:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n[some people may see this message twice, as I forgot to check if the\ncopy I received had \"Some A . Body\" not enclosed in dq; blindly\ndoing \"Reply-All\" ended up listing an invalid address on my Cc: line\nand dropped by vger. apologies]\n\n> diff --git a/git-stash.sh b/git-stash.sh\n> index a184b1e274..1446fbe2e8 100755\n> --- a/git-stash.sh\n> +++ b/git-stash.sh\n> @@ -67,51 +67,20 @@ create_stash () {\n>  \t\tcase \"$1\" in\n>  \t\t-m|--message)\n>  \t\t\tshift\n> -\t\t\ttest -z ${1+x} && usage\n> -\t\t\tstash_msg=\"$1\"\n> -\t\t\tnew_style=t\n> +\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n>  \t\t\t;;\n\nDid you mean ${1?\"BUG: ...\"} here and also \"-u\" below?\n\n>  \t\t-u|--include-untracked)\n>  \t\t\tshift\n> -\t\t\ttest -z ${1+x} && usage\n> -\t\t\tuntracked=\"$1\"\n> -\t\t\tnew_style=t\n> +\t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n>  \t\t\t;;\n\nOther than that the whole series looked sensible to me.\n\nThanks, will replace but that may not happen today.\n"},{"id":"311973","messageId":"20170217231246.GI652@hank","threadId":"45122","inReplyTo":"xmqqfujcpgky.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-17T23:12:46Z","receivedAt":"2017-02-17T23:12:13Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/17, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> [some people may see this message twice, as I forgot to check if the\n> copy I received had \"Some A . Body\" not enclosed in dq; blindly\n> doing \"Reply-All\" ended up listing an invalid address on my Cc: line\n> and dropped by vger. apologies]\n> \n> > diff --git a/git-stash.sh b/git-stash.sh\n> > index a184b1e274..1446fbe2e8 100755\n> > --- a/git-stash.sh\n> > +++ b/git-stash.sh\n> > @@ -67,51 +67,20 @@ create_stash () {\n> >  \t\tcase \"$1\" in\n> >  \t\t-m|--message)\n> >  \t\t\tshift\n> > -\t\t\ttest -z ${1+x} && usage\n> > -\t\t\tstash_msg=\"$1\"\n> > -\t\t\tnew_style=t\n> > +\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n> >  \t\t\t;;\n> \n> Did you mean ${1?\"BUG: ...\"} here and also \"-u\" below?\n\nYeah, shell scripts are still confusing me sometimes.  Thanks for\ncatching.  Would you mind fixing this up while queuing or do you want\nme to resend?\n\n> >  \t\t-u|--include-untracked)\n> >  \t\t\tshift\n> > -\t\t\ttest -z ${1+x} && usage\n> > -\t\t\tuntracked=\"$1\"\n> > -\t\t\tnew_style=t\n> > +\t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n> >  \t\t\t;;\n> \n> Other than that the whole series looked sensible to me.\n> \n> Thanks, will replace but that may not happen today.\n\nThanks!\n"},{"id":"311975","messageId":"xmqq37fcpfza.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170217231246.GI652@hank","subject":"Re: [PATCH v5 0/6] stash: support pathspec argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-17T23:14:33Z","receivedAt":"2017-02-17T23:14:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> On 02/17, Junio C Hamano wrote:\n>> Thomas Gummerer <t.gummerer@gmail.com> writes:\n>> \n>> [some people may see this message twice, as I forgot to check if the\n>> copy I received had \"Some A . Body\" not enclosed in dq; blindly\n>> doing \"Reply-All\" ended up listing an invalid address on my Cc: line\n>> and dropped by vger. apologies]\n>> \n>> > diff --git a/git-stash.sh b/git-stash.sh\n>> > index a184b1e274..1446fbe2e8 100755\n>> > --- a/git-stash.sh\n>> > +++ b/git-stash.sh\n>> > @@ -67,51 +67,20 @@ create_stash () {\n>> >  \t\tcase \"$1\" in\n>> >  \t\t-m|--message)\n>> >  \t\t\tshift\n>> > -\t\t\ttest -z ${1+x} && usage\n>> > -\t\t\tstash_msg=\"$1\"\n>> > -\t\t\tnew_style=t\n>> > +\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n>> >  \t\t\t;;\n>> \n>> Did you mean ${1?\"BUG: ...\"} here and also \"-u\" below?\n>\n> Yeah, shell scripts are still confusing me sometimes.  Thanks for\n> catching.  Would you mind fixing this up while queuing or do you want\n> me to resend?\n\nI'll fix it up myself (please remind me if you notice that I forgot ;-).\n"},{"id":"311989","messageId":"20170217234647.bqhzzm533oruhr5e@sigill.intra.peff.net","threadId":"45122","inReplyTo":"20170217224141.19183-7-t.gummerer@gmail.com","subject":"Re: [PATCH v5 6/6] stash: allow pathspecs in the no verb form","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-17T23:46:47Z","receivedAt":"2017-02-17T23:46:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Feb 17, 2017 at 10:41:41PM +0000, Thomas Gummerer wrote:\n\n> Now that stash_push is used in the no verb form of stash, allow\n> specifying the command line for this form as well.  Always use -- to\n> disambiguate pathspecs from other non-option arguments.\n\nI think that makes sense.\n\n> Also make git stash -p an alias for git stash push -p.  This allows\n> users to use git stash -p <pathspec>.\n\nAnd I think of all the options we discussed for handling \"-p\", I think\nthis one makes the most sense.\n\nIt may be worth calling out in the documentation that this is how it\nworks though, so people do not think that:\n\n  git stash -k -p <path>\n\nwould work (\"git stash -k -p\" _does_ happen to work due to the old\noptions-only rule, but I think we should advertise the general form as\n\"-p is an alias for \"push -p\").\n\n-Peff\n"},{"id":"311990","messageId":"20170217234805.glvhyfbxab6nwgb7@sigill.intra.peff.net","threadId":"45122","inReplyTo":"20170217224141.19183-4-t.gummerer@gmail.com","subject":"Re: [PATCH v5 3/6] stash: refactor stash_create","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-17T23:48:05Z","receivedAt":"2017-02-17T23:48:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Feb 17, 2017 at 10:41:38PM +0000, Thomas Gummerer wrote:\n\n> Refactor the internal stash_create function to use a -m flag for\n> specifying the message and -u flag to indicate whether untracked files\n> should be added to the stash.\n> \n> This makes it easier to pass a pathspec argument to stash_create in the\n> next patch.\n> \n> The user interface for git stash create stays the same.\n\nSounds good, but...\n\n> diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\n> index 2e9cef06e6..d93c47446a 100644\n> --- a/Documentation/git-stash.txt\n> +++ b/Documentation/git-stash.txt\n> @@ -17,6 +17,7 @@ SYNOPSIS\n>  \t     [-u|--include-untracked] [-a|--all] [<message>]]\n>  'git stash' clear\n>  'git stash' create [<message>]\n> +'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n>  'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n\nShould this hunk be dropped from the manpage, then?\n\nI think there is a similar one in the next patch that adds the\n\"pathspec\" argument, and should be dropped, too.\n\n-Peff\n"},{"id":"312071","messageId":"20170219091714.GJ652@hank","threadId":"45122","inReplyTo":"20170217234805.glvhyfbxab6nwgb7@sigill.intra.peff.net","subject":"Re: [PATCH v5 3/6] stash: refactor stash_create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T09:17:14Z","receivedAt":"2017-02-19T09:16:42Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/17, Jeff King wrote:\n> On Fri, Feb 17, 2017 at 10:41:38PM +0000, Thomas Gummerer wrote:\n> \n> > Refactor the internal stash_create function to use a -m flag for\n> > specifying the message and -u flag to indicate whether untracked files\n> > should be added to the stash.\n> > \n> > This makes it easier to pass a pathspec argument to stash_create in the\n> > next patch.\n> > \n> > The user interface for git stash create stays the same.\n> \n> Sounds good, but...\n> \n> > diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\n> > index 2e9cef06e6..d93c47446a 100644\n> > --- a/Documentation/git-stash.txt\n> > +++ b/Documentation/git-stash.txt\n> > @@ -17,6 +17,7 @@ SYNOPSIS\n> >  \t     [-u|--include-untracked] [-a|--all] [<message>]]\n> >  'git stash' clear\n> >  'git stash' create [<message>]\n> > +'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n> >  'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n> \n> Should this hunk be dropped from the manpage, then?\n> \n> I think there is a similar one in the next patch that adds the\n> \"pathspec\" argument, and should be dropped, too.\n\nArgh yes I should have been more careful.  Thanks for catching.\n\n> -Peff\n"},{"id":"312072","messageId":"20170219091833.GK652@hank","threadId":"45122","inReplyTo":"20170217234647.bqhzzm533oruhr5e@sigill.intra.peff.net","subject":"Re: [PATCH v5 6/6] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T09:18:33Z","receivedAt":"2017-02-19T09:17:59Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/17, Jeff King wrote:\n> On Fri, Feb 17, 2017 at 10:41:41PM +0000, Thomas Gummerer wrote:\n> \n> > Now that stash_push is used in the no verb form of stash, allow\n> > specifying the command line for this form as well.  Always use -- to\n> > disambiguate pathspecs from other non-option arguments.\n> \n> I think that makes sense.\n> \n> > Also make git stash -p an alias for git stash push -p.  This allows\n> > users to use git stash -p <pathspec>.\n> \n> And I think of all the options we discussed for handling \"-p\", I think\n> this one makes the most sense.\n> \n> It may be worth calling out in the documentation that this is how it\n> works though, so people do not think that:\n> \n>   git stash -k -p <path>\n> \n> would work (\"git stash -k -p\" _does_ happen to work due to the old\n> options-only rule, but I think we should advertise the general form as\n> \"-p is an alias for \"push -p\").\n\nYeah, I think adding something about this in the documentation would\nbe good.  I'll add a paragraph about this in the re-roll.\n\n> -Peff\n\n"},{"id":"312073","messageId":"20170219110313.24070-6-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 5/6] stash: use stash_push for no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:12Z","receivedAt":"2017-02-19T11:10:05Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have stash_push, which accepts pathspec arguments, use\nit instead of stash_save in git stash without any additional verbs.\n\nPreviously we allowed git stash -- -message, which is no longer allowed\nafter this patch.  Messages starting with a hyphen was allowed since\n3c2eb80f, (\"stash: simplify defaulting to \"save\" and reject unknown\noptions\").  However it was never the intent to allow that, but rather it\nwas allowed accidentally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  8 ++++----\n git-stash.sh                | 16 ++++++++--------\n t/t3903-stash.sh            |  4 +---\n 3 files changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex b7db939a06..3f7fa88ddc 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,11 +13,11 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\ndiff --git a/git-stash.sh b/git-stash.sh\nindex b55983d1fd..1e55cd5fdd 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,11 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n-   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t      [-- <pathspec>...]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -667,7 +667,7 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n@@ -677,7 +677,7 @@ do\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -728,7 +728,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 4fb800eec8..7f90a247b4 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312074","messageId":"20170219110313.24070-1-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170217224141.19183-1-t.gummerer@gmail.com","subject":"[PATCH v6 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:07Z","receivedAt":"2017-02-19T11:10:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Thanks Junio and Peff for comments on the last round.\n\nChanges since then:\n\n- removed mention of the \"new form\" of git stash create from the\n  Documentation.\n- Changed documentation for git stash without a verb, mentioning\n  stash -p now being an alias for git stash push -p and that -- can be\n  used as disambiguation for for pathspecs\n- Fixed ${1-...} which should have been ${1?...}\n- Removed unused new_style variable from create_stash, which was a\n  leftover from perious rounds.\n\nInterdiff below:\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 97194576ef..369bfae33d 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -20,8 +20,6 @@ SYNOPSIS\n \t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n-'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>]\n-\t     [-- <pathspec>...]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n \n DESCRIPTION\n@@ -55,10 +53,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \n \tSave your local modifications to a new 'stash', and run `git reset\n \t--hard` to revert them.  The <message> part is optional and gives\n-\tthe description along with the stashed state.  For quickly making\n-\ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n-\tonly <message> does not trigger this action to prevent a misspelled\n-\tsubcommand from making an unwanted stash.\n+\tthe description along with the stashed state.\n++\n+For quickly making a snapshot, you can omit \"push\".  In this mode,\n+non-option arguments are not allowed to prevent a misspelled\n+subcommand from making an unwanted stash.  The two exceptions to this\n+are `stash -p` which acts as alias for `stash push -p` and pathspecs,\n+which are allowed after a double hyphen `--` for disambiguation.\n +\n When pathspec is given to 'git stash push', the new stash records the\n modified states only for the files that match the pathspec.  The index\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 1446fbe2e8..18aba1346f 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -61,17 +61,16 @@ clear_stash () {\n create_stash () {\n \tstash_msg=\n \tuntracked=\n-\tnew_style=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n \t\t-m|--message)\n \t\t\tshift\n-\t\t\tstash_msg=${1-\"BUG: create_stash () -m requires an argument\"}\n+\t\t\tstash_msg=${1?\"BUG: create_stash () -m requires an argument\"}\n \t\t\t;;\n \t\t-u|--include-untracked)\n \t\t\tshift\n-\t\t\tuntracked=${1-\"BUG: create_stash () -u requires an argument\"}\n+\t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n \t\t--)\n \t\t\tshift\n\nThomas Gummerer (6):\n  stash: introduce push verb\n  stash: add test for the create command line arguments\n  stash: refactor stash_create\n  stash: teach 'push' (and 'create_stash') to honor pathspec\n  stash: use stash_push for no verb form\n  stash: allow pathspecs in the no verb form\n\n Documentation/git-stash.txt        |  27 ++++++--\n git-stash.sh                       | 127 ++++++++++++++++++++++++++++++-------\n t/t3903-stash.sh                   | 118 +++++++++++++++++++++++++++++++++-\n t/t3905-stash-include-untracked.sh |  26 ++++++++\n 4 files changed, 267 insertions(+), 31 deletions(-)\n\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312075","messageId":"20170219110313.24070-3-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 2/6] stash: add test for the create command line arguments","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:09Z","receivedAt":"2017-02-19T11:10:20Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently there is no test showing the expected behaviour of git stash\ncreate's command line arguments.  Add a test for that to show the\ncurrent expected behaviour and to make sure future refactorings don't\nbreak those expectations.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/t3903-stash.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 3577115807..ffe3549ea5 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -784,4 +784,22 @@ test_expect_success 'push -m shows right message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create \"create test message\") &&\n+\techo \"On master: create test message\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'create with multiple arguments for the message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create test untracked) &&\n+\techo \"On master: test untracked\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312076","messageId":"20170219110313.24070-4-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 3/6] stash: refactor stash_create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:10Z","receivedAt":"2017-02-19T11:11:20Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Refactor the internal stash_create function to use a -m flag for\nspecifying the message and -u flag to indicate whether untracked files\nshould be added to the stash.\n\nThis makes it easier to pass a pathspec argument to stash_create in the\nnext patch.\n\nThe user interface for git stash create stays the same.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh | 22 ++++++++++++++++++----\n 1 file changed, 18 insertions(+), 4 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8365ebba2a..ef5d1b45be 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -58,8 +58,22 @@ clear_stash () {\n }\n \n create_stash () {\n-\tstash_msg=\"$1\"\n-\tuntracked=\"$2\"\n+\tstash_msg=\n+\tuntracked=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\tstash_msg=${1?\"BUG: create_stash () -m requires an argument\"}\n+\t\t\t;;\n+\t\t-u|--include-untracked)\n+\t\t\tshift\n+\t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \n \tgit update-index -q --refresh\n \tif no_changes\n@@ -268,7 +282,7 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash \"$stash_msg\" $untracked\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n@@ -667,7 +681,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$*\" && echo \"$w_commit\"\n+\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312077","messageId":"20170219110313.24070-2-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 1/6] stash: introduce push verb","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:08Z","receivedAt":"2017-02-19T11:11:31Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Introduce a new git stash push verb in addition to git stash save.  The\npush verb is used to transition from the current command line arguments\nto a more conventional way, in which the message is given as an argument\nto the -m option.\n\nThis allows us to have pathspecs at the end of the command line\narguments like other Git commands do, so that the user can say which\nsubset of paths to stash (and leave others behind).\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  3 +++\n git-stash.sh                | 46 ++++++++++++++++++++++++++++++++++++++++++---\n t/t3903-stash.sh            |  9 +++++++++\n 3 files changed, 55 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9cef06e6..0f602ea0c8 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -15,6 +15,8 @@ SYNOPSIS\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n+'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -46,6 +48,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n \n \tSave your local modifications to a new 'stash', and run `git reset\n \t--hard` to revert them.  The <message> part is optional and gives\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..8365ebba2a 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -9,6 +9,8 @@ USAGE=\"list [<options>]\n    or: $dashless branch <branchname> [<stash>]\n    or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -189,10 +191,11 @@ store_stash () {\n \treturn $ret\n }\n \n-save_stash () {\n+push_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tstash_msg=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +219,11 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -251,8 +259,6 @@ save_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n-\tstash_msg=\"$*\"\n-\n \tgit update-index -q --refresh\n \tif no_changes\n \tthen\n@@ -291,6 +297,36 @@ save_stash () {\n \tfi\n }\n \n+save_stash () {\n+\tpush_options=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\t# pass all options through to push_stash\n+\t\t\tpush_options=\"$push_options $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tstash_msg=\"$*\"\n+\n+\tif test -z \"$stash_msg\"\n+\tthen\n+\t\tpush_stash $push_options\n+\telse\n+\t\tpush_stash $push_options -m \"$stash_msg\"\n+\tfi\n+}\n+\n have_stash () {\n \tgit rev-parse --verify --quiet $ref_stash >/dev/null\n }\n@@ -617,6 +653,10 @@ save)\n \tshift\n \tsave_stash \"$@\"\n \t;;\n+push)\n+\tshift\n+\tpush_stash \"$@\"\n+\t;;\n apply)\n \tshift\n \tapply_stash \"$@\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2de3e18ce6..3577115807 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,13 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'push -m shows right message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit stash push -m \"test message\" &&\n+\techo \"stash@{0}: On master: test message\" >expect &&\n+\tgit stash list -1 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312078","messageId":"20170219110313.24070-5-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:11Z","receivedAt":"2017-02-19T11:11:37Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"While working on a repository, it's often helpful to stash the changes\nof a single or multiple files, and leave others alone.  Unfortunately\ngit currently offers no such option.  git stash -p can be used to work\naround this, but it's often impractical when there are a lot of changes\nover multiple files.\n\nAllow 'git stash push' to take pathspec to specify which paths to stash.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt        |  9 ++++-\n git-stash.sh                       | 48 +++++++++++++++++++------\n t/t3903-stash.sh                   | 72 ++++++++++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh | 26 ++++++++++++++\n 4 files changed, 143 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 0f602ea0c8..b7db939a06 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n 'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n+\t     [--] [<pathspec>...]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -48,7 +49,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n-push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n \tSave your local modifications to a new 'stash', and run `git reset\n \t--hard` to revert them.  The <message> part is optional and gives\n@@ -57,6 +58,12 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tonly <message> does not trigger this action to prevent a misspelled\n \tsubcommand from making an unwanted stash.\n +\n+When pathspec is given to 'git stash push', the new stash records the\n+modified states only for the files that match the pathspec.  The index\n+entries and working tree files are then rolled back to the state in\n+HEAD only for these files, too, leaving files that do not match the\n+pathspec intact.\n++\n If the `--keep-index` option is used, all changes already added to the\n index are left intact.\n +\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ef5d1b45be..b55983d1fd 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -11,6 +11,7 @@ USAGE=\"list [<options>]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n    or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t      [-- <pathspec>...]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -35,15 +36,15 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n untracked_files () {\n \texcl_opt=--exclude-standard\n \ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt\n+\tgit ls-files -o -z $excl_opt -- \"$@\"\n }\n \n clear_stash () {\n@@ -71,12 +72,16 @@ create_stash () {\n \t\t\tshift\n \t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n \t\tesac\n \t\tshift\n \tdone\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -108,7 +113,7 @@ create_stash () {\n \t\t# Untracked files are stored by themselves in a parentless commit, for\n \t\t# ease of unpacking later.\n \t\tu_commit=$(\n-\t\t\tuntracked_files | (\n+\t\t\tuntracked_files \"$@\" | (\n \t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\t\texport GIT_INDEX_FILE &&\n \t\t\t\trm -f \"$TMPindex\" &&\n@@ -131,7 +136,7 @@ create_stash () {\n \t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n \t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- >\"$TMP-stagenames\" &&\n+\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n \t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n \t\t\tgit write-tree &&\n \t\t\trm -f \"$TMPindex\"\n@@ -145,7 +150,7 @@ create_stash () {\n \n \t\t# find out what the user wants\n \t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- &&\n+\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -274,7 +279,7 @@ push_stash () {\n \tfi\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n@@ -282,18 +287,39 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tif test $# != 0\n+\t\tthen\n+\t\t\tsaved_untracked=\n+\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tsaved_untracked=$(\n+\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n+\t\t\t\t\t    xargs -0 git stash create -u all --)\n+\t\t\tfi\n+\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n+\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n+\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n+\t\t\tthen\n+\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n+\t\t\tfi\n+\t\t\tif test -n \"$saved_untracked\"\n+\t\t\tthen\n+\t\t\t\tgit stash pop -q $saved_untracked\n+\t\t\tfi\n+\t\telse\n+\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tfi\n \t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n \t\tif test -n \"$untracked\"\n \t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION\n+\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex ffe3549ea5..4fb800eec8 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -802,4 +802,76 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'stash -- <filename> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with multiple filename arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only onece' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push -p not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>file &&\n+\tgit add file &&\n+\tgit stash push not-file >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'untracked file is not removed when using pathspecs' '\n+\t>untracked &&\n+\tgit stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n+\ttest_path_is_file untracked\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex f372fc8ca8..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '\n \ttest -s .gitignore\n '\n \n+test_expect_success 'stash push --include-untracked with pathspec' '\n+\t>foo &&\n+\t>bar &&\n+\tgit stash push --include-untracked -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file foo\n+'\n+\n+test_expect_success 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312079","messageId":"20170219110313.24070-7-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v6 6/6] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-19T11:03:13Z","receivedAt":"2017-02-19T11:12:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that stash_push is used in the no verb form of stash, allow\nspecifying the command line for this form as well.  Always use -- to\ndisambiguate pathspecs from other non-option arguments.\n\nAlso make git stash -p an alias for git stash push -p.  This allows\nusers to use git stash -p <pathspec>.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt | 11 +++++++----\n git-stash.sh                |  3 +++\n t/t3903-stash.sh            | 15 +++++++++++++++\n 3 files changed, 25 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 3f7fa88ddc..369bfae33d 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -53,10 +53,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \n \tSave your local modifications to a new 'stash', and run `git reset\n \t--hard` to revert them.  The <message> part is optional and gives\n-\tthe description along with the stashed state.  For quickly making\n-\ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n-\tonly <message> does not trigger this action to prevent a misspelled\n-\tsubcommand from making an unwanted stash.\n+\tthe description along with the stashed state.\n++\n+For quickly making a snapshot, you can omit \"push\".  In this mode,\n+non-option arguments are not allowed to prevent a misspelled\n+subcommand from making an unwanted stash.  The two exceptions to this\n+are `stash -p` which acts as alias for `stash push -p` and pathspecs,\n+which are allowed after a double hyphen `--` for disambiguation.\n +\n When pathspec is given to 'git stash push', the new stash records the\n modified states only for the files that match the pathspec.  The index\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 1e55cd5fdd..18aba1346f 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -666,12 +666,15 @@ apply_to_branch () {\n \t}\n }\n \n+test \"$1\" = \"-p\" && set \"push\" \"$@\"\n+\n PARSE_CACHE='--not-parsed'\n # The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 7f90a247b4..c0ae41e724 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -872,4 +872,19 @@ test_expect_success 'untracked files are left in place when -u is not given' '\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.12.0.rc2.399.g0ca89a282\n\n"},{"id":"312126","messageId":"20170220075742.6a2irsjlukobnju4@sigill.intra.peff.net","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"Re: [PATCH v6 0/6] stash: support pathspec argument","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-20T07:57:42Z","receivedAt":"2017-02-20T07:58:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Feb 19, 2017 at 11:03:07AM +0000, Thomas Gummerer wrote:\n\n> Thanks Junio and Peff for comments on the last round.\n> \n> Changes since then:\n> \n> - removed mention of the \"new form\" of git stash create from the\n>   Documentation.\n> - Changed documentation for git stash without a verb, mentioning\n>   stash -p now being an alias for git stash push -p and that -- can be\n>   used as disambiguation for for pathspecs\n> - Fixed ${1-...} which should have been ${1?...}\n> - Removed unused new_style variable from create_stash, which was a\n>   leftover from perious rounds.\n\nI gave it one more read-through, and didn't see anything objectionable.\nThanks for seeing this through!\n\n-Peff\n"},{"id":"312129","messageId":"xmqq8tp1l19z.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"Re: [PATCH v6 0/6] stash: support pathspec argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-20T08:22:32Z","receivedAt":"2017-02-20T08:22:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> @@ -55,10 +53,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n>  \n>  \tSave your local modifications to a new 'stash', and run `git reset\n>  \t--hard` to revert them.  The <message> part is optional and gives\n\nI didn't notice this during v5 review, but the above seems to be\nbased on the codebase before your documentation update (which used\nto be part of the series in older iteration).  I had to tweak the\nseries to apply on top of your 20a7e06172 (\"Documentation/stash:\nremove mention of git reset --hard\", 2017-02-12) while queuing, so\nplease double check the result when it is pushed out to 'pu'.\n\nThanks.\n"},{"id":"312160","messageId":"xmqqd1eck5x5.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"Re: [PATCH v6 0/6] stash: support pathspec argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-20T19:39:50Z","receivedAt":"2017-02-20T19:39:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> @@ -55,10 +53,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n>  \n>  \tSave your local modifications to a new 'stash', and run `git reset\n>  \t--hard` to revert them.  The <message> part is optional and gives\n\nI didn't notice this during v5 review, but the above seems to be\nbased on the codebase before your documentation update (which used\nto be part of the series in older iteration).  I had to tweak the\nseries to apply on top of your 20a7e06172 (\"Documentation/stash:\nremove mention of git reset --hard\", 2017-02-12) while queuing, so\nplease double check the result when it is pushed out to 'pu'.\n\nThanks.\n"},{"id":"312205","messageId":"xmqqmvdfh4az.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170219110313.24070-5-t.gummerer@gmail.com","subject":"Re: [PATCH v6 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-21T16:55:16Z","receivedAt":"2017-02-21T16:55:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> -\t\tgit reset --hard ${GIT_QUIET:+-q}\n\nThis hunk is probably the most important one to review in the whole\nseries, in the sense that these are entirely new code that didn't\nexist in the original.\n\n> +\t\tif test $# != 0\n> +\t\tthen\n> +\t\t\tsaved_untracked=\n> +\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n\nI notice that \"ls-files -o\" used in the code before this series are\nalmost always used with --exclude-standard but we do not set up the\nstandard exclude pattern here.  Is there a good reason to use (or\nnot to use) it here as well?\n\n> +\t\t\tthen\n> +\t\t\t\tsaved_untracked=$(\n> +\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n> +\t\t\t\t\t    xargs -0 git stash create -u all --)\n> +\t\t\tfi\n\nRunning the same ls-files twice look somewhat wasteful.\n\nI suspect that we avoid \"xargs -0\" in our code from portability\nconcern (isn't it a GNU invention?)\n\n> +\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n\nHmm, am I being naive to suspect that the above is a roundabout way\nto say:\n\n\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n\nor is an effect quite different from that intended here?\n\n> +\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n\nLikewise.  Wouldn't the above be equivalent to:\n\n\tgit checkout ${GIT_QUIET:+-q} HEAD -- \"$@\"\n\nOr is this trying to preserve paths modified in the working tree and\nfully added to the index?\n\n\n> +\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n> +\t\t\tthen\n> +\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n\nLikewise.  \"ls-files --others\" being the major part of what \"clean\"\nis about, I suspect the \"ls-files piped to clean\" is redundant.  Do\nyou even need a test?  IOW, doesn't \"git clean\" with a pathspec that\ndoes not match anything silently succeed without doing anything\nharmful?\n\n> +\t\t\tfi\n> +\t\t\tif test -n \"$saved_untracked\"\n> +\t\t\tthen\n> +\t\t\t\tgit stash pop -q $saved_untracked\n\nI see this thing was \"created\", and the whole point of \"create\" is\nto be different from \"save/push\" that automatically adds the result\nto the stash reflog.  Should we be \"pop\"ing it, or did you mean to\njust call apply_stash on it?\n\n> +\t\t\tfi\n> +\t\telse\n> +\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n> +\t\tfi\n\n"},{"id":"312638","messageId":"20170225155719.GA6243@hank","threadId":"45122","inReplyTo":"xmqqd1eck5x5.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v6 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T15:57:19Z","receivedAt":"2017-02-25T15:00:13Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/20, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > @@ -55,10 +53,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n> >  \n> >  \tSave your local modifications to a new 'stash', and run `git reset\n> >  \t--hard` to revert them.  The <message> part is optional and gives\n> \n> I didn't notice this during v5 review, but the above seems to be\n> based on the codebase before your documentation update (which used\n> to be part of the series in older iteration).  I had to tweak the\n> series to apply on top of your 20a7e06172 (\"Documentation/stash:\n> remove mention of git reset --hard\", 2017-02-12) while queuing, so\n> please double check the result when it is pushed out to 'pu'.\n\nSorry about that.  What you queued looks good to me, I will however\nsend a re-roll based on your comments on 4/6.  (And I'll make sure to\nbase it on 20a7e06172)\n"},{"id":"312647","messageId":"20170225202733.GB6243@hank","threadId":"45122","inReplyTo":"xmqqmvdfh4az.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v6 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T20:27:33Z","receivedAt":"2017-02-25T19:22:21Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/21, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > -\t\tgit reset --hard ${GIT_QUIET:+-q}\n> \n> This hunk is probably the most important one to review in the whole\n> series, in the sense that these are entirely new code that didn't\n> exist in the original.\n> \n> > +\t\tif test $# != 0\n> > +\t\tthen\n> > +\t\t\tsaved_untracked=\n> > +\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n> \n> I notice that \"ls-files -o\" used in the code before this series are\n> almost always used with --exclude-standard but we do not set up the\n> standard exclude pattern here.  Is there a good reason to use (or\n> not to use) it here as well?\n\nWe probably should use it, not adding it was an oversight.\n\n> > +\t\t\tthen\n> > +\t\t\t\tsaved_untracked=$(\n> > +\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n> > +\t\t\t\t\t    xargs -0 git stash create -u all --)\n> > +\t\t\tfi\n> \n> Running the same ls-files twice look somewhat wasteful.\n> \n> I suspect that we avoid \"xargs -0\" in our code from portability\n> concern (isn't it a GNU invention?)\n> \n> > +\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n> \n> Hmm, am I being naive to suspect that the above is a roundabout way\n> to say:\n> \n> \tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> \n> or is an effect quite different from that intended here?\n> \n> > +\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n> \n> Likewise.  Wouldn't the above be equivalent to:\n> \n> \tgit checkout ${GIT_QUIET:+-q} HEAD -- \"$@\"\n> \n> Or is this trying to preserve paths modified in the working tree and\n> fully added to the index?.\n\nNo, it's not trying to do that (all the paths we're touching here\nwould have been \"reset\" earlier, so it wouldn't change anything.\nHowever what this code tried to do is to allow \"stash push -- path\npathspec-not-in-repo\", where \"pathspec-not-in-repo\" would end up\ntripping up \"checkout\" which does not accept pathspecs that are not in\nthe index.\n\nI think we should disallow such pathspecs in stash as well, except in\nthe --include-untracked case, where it still makes sense.\n\nThis means we can't get rid of the \"ls-files --modified\" here, but we\ncan in all other places, and get rid of the \"stash_create\"\n\"stash_apply\" dance to store the untracked files, simplifying this\npart quite a bit.\n\nWill re-roll.\n\n> \n> > +\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n> > +\t\t\tthen\n> > +\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n> \n> Likewise.  \"ls-files --others\" being the major part of what \"clean\"\n> is about, I suspect the \"ls-files piped to clean\" is redundant.  Do\n> you even need a test?  IOW, doesn't \"git clean\" with a pathspec that\n> does not match anything silently succeed without doing anything\n> harmful?\n>\n> > +\t\t\tfi\n> > +\t\t\tif test -n \"$saved_untracked\"\n> > +\t\t\tthen\n> > +\t\t\t\tgit stash pop -q $saved_untracked\n> \n> I see this thing was \"created\", and the whole point of \"create\" is\n> to be different from \"save/push\" that automatically adds the result\n> to the stash reflog.  Should we be \"pop\"ing it, or did you mean to\n> just call apply_stash on it?\n>\n> > +\t\t\tfi\n> > +\t\telse\n> > +\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n> > +\t\tfi\n> \n"},{"id":"312655","messageId":"20170225213306.2410-3-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 2/6] stash: add test for the create command line arguments","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:02Z","receivedAt":"2017-02-25T20:28:38Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently there is no test showing the expected behaviour of git stash\ncreate's command line arguments.  Add a test for that to show the\ncurrent expected behaviour and to make sure future refactorings don't\nbreak those expectations.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/t3903-stash.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 3577115807..ffe3549ea5 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -784,4 +784,22 @@ test_expect_success 'push -m shows right message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create \"create test message\") &&\n+\techo \"On master: create test message\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'create with multiple arguments for the message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create test untracked) &&\n+\techo \"On master: test untracked\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312656","messageId":"20170225213306.2410-4-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 3/6] stash: refactor stash_create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:03Z","receivedAt":"2017-02-25T20:28:39Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Refactor the internal stash_create function to use a -m flag for\nspecifying the message and -u flag to indicate whether untracked files\nshould be added to the stash.\n\nThis makes it easier to pass a pathspec argument to stash_create in the\nnext patch.\n\nThe user interface for git stash create stays the same.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh | 22 ++++++++++++++++++----\n 1 file changed, 18 insertions(+), 4 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8365ebba2a..ef5d1b45be 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -58,8 +58,22 @@ clear_stash () {\n }\n \n create_stash () {\n-\tstash_msg=\"$1\"\n-\tuntracked=\"$2\"\n+\tstash_msg=\n+\tuntracked=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\tstash_msg=${1?\"BUG: create_stash () -m requires an argument\"}\n+\t\t\t;;\n+\t\t-u|--include-untracked)\n+\t\t\tshift\n+\t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \n \tgit update-index -q --refresh\n \tif no_changes\n@@ -268,7 +282,7 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash \"$stash_msg\" $untracked\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n@@ -667,7 +681,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$*\" && echo \"$w_commit\"\n+\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312657","messageId":"20170225213306.2410-7-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 6/6] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:06Z","receivedAt":"2017-02-25T20:29:02Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that stash_push is used in the no verb form of stash, allow\nspecifying the command line for this form as well.  Always use -- to\ndisambiguate pathspecs from other non-option arguments.\n\nAlso make git stash -p an alias for git stash push -p.  This allows\nusers to use git stash -p <pathspec>.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt | 11 +++++++----\n git-stash.sh                |  3 +++\n t/t3903-stash.sh            | 15 +++++++++++++++\n 3 files changed, 25 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 4d8d30f179..70191d06b6 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -54,10 +54,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\n \tThe <message> part is optional and gives\n-\tthe description along with the stashed state.  For quickly making\n-\ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n-\tonly <message> does not trigger this action to prevent a misspelled\n-\tsubcommand from making an unwanted stash.\n+\tthe description along with the stashed state.\n++\n+For quickly making a snapshot, you can omit \"push\".  In this mode,\n+non-option arguments are not allowed to prevent a misspelled\n+subcommand from making an unwanted stash.  The two exceptions to this\n+are `stash -p` which acts as alias for `stash push -p` and pathspecs,\n+which are allowed after a double hyphen `--` for disambiguation.\n +\n When pathspec is given to 'git stash push', the new stash records the\n modified states only for the files that match the pathspec.  The index\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 2d7b30ec5e..28d0624c75 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -655,12 +655,15 @@ apply_to_branch () {\n \t}\n }\n \n+test \"$1\" = \"-p\" && set \"push\" \"$@\"\n+\n PARSE_CACHE='--not-parsed'\n # The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2f5888df0d..f7733b4dd4 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -876,4 +876,19 @@ test_expect_success 'untracked files are left in place when -u is not given' '\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312658","messageId":"20170225213306.2410-1-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170219110313.24070-1-t.gummerer@gmail.com","subject":"[PATCH v7 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:00Z","receivedAt":"2017-02-25T20:29:36Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Thanks Junio for more comments on the last round, and Peff for reading\nthrough it as well.\n\nChanges since v6:\n\n- If no --include-untracked option is given to git stash push, and a\n  pathspec is not in the repository, error out instead of ignoring\n  it.  This brings it in line with things like checkout, and also\n  allows us to simplify the code internally.\n- Simplify the code for rolling back the changes from the working\n  tree.  This is enabled by the changes to the pathspec handling.\n- There's no more \"xargs -0\", so there should be no more portability\n  concerns.\n- Adjust the tests and improve some of the titles a bit\n\nInterdiff:\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 18aba1346f..28d0624c75 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -278,12 +278,15 @@ push_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n+\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n+\n \tgit update-index -q --refresh\n \tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n \tfi\n+\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n@@ -296,23 +299,9 @@ push_stash () {\n \tthen\n \t\tif test $# != 0\n \t\tthen\n-\t\t\tsaved_untracked=\n-\t\t\tif test -n \"$(git ls-files --others -- \"$@\")\"\n-\t\t\tthen\n-\t\t\t\tsaved_untracked=$(\n-\t\t\t\t\tgit ls-files -z --others -- \"$@\" |\n-\t\t\t\t\t    xargs -0 git stash create -u all --)\n-\t\t\tfi\n-\t\t\tgit ls-files -z -- \"$@\" | xargs -0 git reset ${GIT_QUIET:+-q} --\n-\t\t\tgit ls-files -z --modified -- \"$@\" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD --\n-\t\t\tif test -n \"$(git ls-files -z --others -- \"$@\")\"\n-\t\t\tthen\n-\t\t\t\tgit ls-files -z --others -- \"$@\" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} --\n-\t\t\tfi\n-\t\t\tif test -n \"$saved_untracked\"\n-\t\t\tthen\n-\t\t\t\tgit stash pop -q $saved_untracked\n-\t\t\tfi\n+\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n+\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n+\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n \t\telse\n \t\t\tgit reset --hard ${GIT_QUIET:+-q}\n \t\tfi\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex c0ae41e724..f7733b4dd4 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -800,7 +800,7 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'stash -- <filename> stashes and restores the file' '\n+test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n \t>foo &&\n \t>bar &&\n \tgit add foo bar &&\n@@ -812,7 +812,7 @@ test_expect_success 'stash -- <filename> stashes and restores the file' '\n \ttest_path_is_file bar\n '\n \n-test_expect_success 'stash with multiple filename arguments' '\n+test_expect_success 'stash with multiple pathspec arguments' '\n \t>foo &&\n \t>bar &&\n \t>extra &&\n@@ -842,25 +842,29 @@ test_expect_success 'stash with file including $IFS character' '\n \ttest_path_is_file bar\n '\n \n-test_expect_success 'stash push -p with pathspec shows no changes only onece' '\n-\t>file &&\n-\tgit add file &&\n-\tgit stash push -p not-file >actual &&\n+test_expect_success 'stash push -p with pathspec shows no changes only once' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push -p foo >actual &&\n \techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'stash push with pathspec shows no changes when there are none' '\n-\t>file &&\n-\tgit add file &&\n-\tgit stash push not-file >actual &&\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push foo >actual &&\n \techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'untracked file is not removed when using pathspecs' '\n+test_expect_success 'stash push with pathspec not in the repository errors out' '\n \t>untracked &&\n-\tgit stash push untracked &&\n+\ttest_must_fail git stash push untracked &&\n \ttest_path_is_file untracked\n '\n \n\nThomas Gummerer (6):\n  stash: introduce push verb\n  stash: add test for the create command line arguments\n  stash: refactor stash_create\n  stash: teach 'push' (and 'create_stash') to honor pathspec\n  stash: use stash_push for no verb form\n  stash: allow pathspecs in the no verb form\n\n Documentation/git-stash.txt        |  25 ++++++--\n git-stash.sh                       | 114 +++++++++++++++++++++++++++-------\n t/t3903-stash.sh                   | 122 ++++++++++++++++++++++++++++++++++++-\n t/t3905-stash-include-untracked.sh |  26 ++++++++\n 4 files changed, 257 insertions(+), 30 deletions(-)\n\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312659","messageId":"20170225213306.2410-2-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 1/6] stash: introduce push verb","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:01Z","receivedAt":"2017-02-25T20:29:37Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Introduce a new git stash push verb in addition to git stash save.  The\npush verb is used to transition from the current command line arguments\nto a more conventional way, in which the message is given as an argument\nto the -m option.\n\nThis allows us to have pathspecs at the end of the command line\narguments like other Git commands do, so that the user can say which\nsubset of paths to stash (and leave others behind).\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  3 +++\n git-stash.sh                | 46 ++++++++++++++++++++++++++++++++++++++++++---\n t/t3903-stash.sh            |  9 +++++++++\n 3 files changed, 55 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9e344cd7..d240df4af7 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -15,6 +15,8 @@ SYNOPSIS\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n+'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -46,6 +48,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n \n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..8365ebba2a 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -9,6 +9,8 @@ USAGE=\"list [<options>]\n    or: $dashless branch <branchname> [<stash>]\n    or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -189,10 +191,11 @@ store_stash () {\n \treturn $ret\n }\n \n-save_stash () {\n+push_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tstash_msg=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +219,11 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -251,8 +259,6 @@ save_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n-\tstash_msg=\"$*\"\n-\n \tgit update-index -q --refresh\n \tif no_changes\n \tthen\n@@ -291,6 +297,36 @@ save_stash () {\n \tfi\n }\n \n+save_stash () {\n+\tpush_options=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\t# pass all options through to push_stash\n+\t\t\tpush_options=\"$push_options $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tstash_msg=\"$*\"\n+\n+\tif test -z \"$stash_msg\"\n+\tthen\n+\t\tpush_stash $push_options\n+\telse\n+\t\tpush_stash $push_options -m \"$stash_msg\"\n+\tfi\n+}\n+\n have_stash () {\n \tgit rev-parse --verify --quiet $ref_stash >/dev/null\n }\n@@ -617,6 +653,10 @@ save)\n \tshift\n \tsave_stash \"$@\"\n \t;;\n+push)\n+\tshift\n+\tpush_stash \"$@\"\n+\t;;\n apply)\n \tshift\n \tapply_stash \"$@\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2de3e18ce6..3577115807 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,13 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'push -m shows right message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit stash push -m \"test message\" &&\n+\techo \"stash@{0}: On master: test message\" >expect &&\n+\tgit stash list -1 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312660","messageId":"20170225213306.2410-5-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:04Z","receivedAt":"2017-02-25T20:29:40Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"While working on a repository, it's often helpful to stash the changes\nof a single or multiple files, and leave others alone.  Unfortunately\ngit currently offers no such option.  git stash -p can be used to work\naround this, but it's often impractical when there are a lot of changes\nover multiple files.\n\nAllow 'git stash push' to take pathspec to specify which paths to stash.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt        |  9 ++++-\n git-stash.sh                       | 37 +++++++++++++------\n t/t3903-stash.sh                   | 76 ++++++++++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh | 26 +++++++++++++\n 4 files changed, 136 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex d240df4af7..88369ed8b6 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n 'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n+\t     [--] [<pathspec>...]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -48,7 +49,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n-push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\n@@ -58,6 +59,12 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tonly <message> does not trigger this action to prevent a misspelled\n \tsubcommand from making an unwanted stash.\n +\n+When pathspec is given to 'git stash push', the new stash records the\n+modified states only for the files that match the pathspec.  The index\n+entries and working tree files are then rolled back to the state in\n+HEAD only for these files, too, leaving files that do not match the\n+pathspec intact.\n++\n If the `--keep-index` option is used, all changes already added to the\n index are left intact.\n +\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ef5d1b45be..57828f926d 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -11,6 +11,7 @@ USAGE=\"list [<options>]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n    or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t      [-- <pathspec>...]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -35,15 +36,15 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n untracked_files () {\n \texcl_opt=--exclude-standard\n \ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt\n+\tgit ls-files -o -z $excl_opt -- \"$@\"\n }\n \n clear_stash () {\n@@ -71,12 +72,16 @@ create_stash () {\n \t\t\tshift\n \t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n \t\tesac\n \t\tshift\n \tdone\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -108,7 +113,7 @@ create_stash () {\n \t\t# Untracked files are stored by themselves in a parentless commit, for\n \t\t# ease of unpacking later.\n \t\tu_commit=$(\n-\t\t\tuntracked_files | (\n+\t\t\tuntracked_files \"$@\" | (\n \t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\t\texport GIT_INDEX_FILE &&\n \t\t\t\trm -f \"$TMPindex\" &&\n@@ -131,7 +136,7 @@ create_stash () {\n \t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n \t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- >\"$TMP-stagenames\" &&\n+\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n \t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n \t\t\tgit write-tree &&\n \t\t\trm -f \"$TMPindex\"\n@@ -145,7 +150,7 @@ create_stash () {\n \n \t\t# find out what the user wants\n \t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- &&\n+\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -273,27 +278,37 @@ push_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n+\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n+\n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n \tfi\n+\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tif test $# != 0\n+\t\tthen\n+\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n+\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n+\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n+\t\telse\n+\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tfi\n \t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n \t\tif test -n \"$untracked\"\n \t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION\n+\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex ffe3549ea5..4d8a096773 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -802,4 +802,80 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with multiple pathspec arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only once' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push -p foo >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push foo >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec not in the repository errors out' '\n+\t>untracked &&\n+\ttest_must_fail git stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n+\ttest_path_is_file untracked\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex f372fc8ca8..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '\n \ttest -s .gitignore\n '\n \n+test_expect_success 'stash push --include-untracked with pathspec' '\n+\t>foo &&\n+\t>bar &&\n+\tgit stash push --include-untracked -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file foo\n+'\n+\n+test_expect_success 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312661","messageId":"20170225213306.2410-6-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v7 5/6] stash: use stash_push for no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-25T21:33:05Z","receivedAt":"2017-02-25T20:29:43Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have stash_push, which accepts pathspec arguments, use\nit instead of stash_save in git stash without any additional verbs.\n\nPreviously we allowed git stash -- -message, which is no longer allowed\nafter this patch.  Messages starting with a hyphen was allowed since\n3c2eb80f, (\"stash: simplify defaulting to \"save\" and reject unknown\noptions\").  However it was never the intent to allow that, but rather it\nwas allowed accidentally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  8 ++++----\n git-stash.sh                | 16 ++++++++--------\n t/t3903-stash.sh            |  4 +---\n 3 files changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 88369ed8b6..4d8d30f179 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,11 +13,11 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 57828f926d..2d7b30ec5e 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,11 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n-   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t      [-- <pathspec>...]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -656,7 +656,7 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n@@ -666,7 +666,7 @@ do\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -717,7 +717,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 4d8a096773..2f5888df0d 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n-- \n2.11.0.301.g275aeb250c.dirty\n\n"},{"id":"312779","messageId":"xmqq60jvwewc.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170225213306.2410-5-t.gummerer@gmail.com","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T20:35:31Z","receivedAt":"2017-02-27T21:37:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> +\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n\nThis silent \"exit 1\" made me scratch my head, but --error-unmatch\nwould have already given an error message, like\n\n    error: pathspec 'no such' did not match any file(s) known to git.\n    Did you forget to 'git add'?\n\nso that would be OK.\n"},{"id":"312784","messageId":"20170227215351.GA17065@hank","threadId":"45122","inReplyTo":"xmqqwpcbuyrd.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-27T21:53:51Z","receivedAt":"2017-02-27T22:05:44Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/27, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> >  \tif test -z \"$patch_mode\"\n> >  \tthen\n> > -\t\tgit reset --hard ${GIT_QUIET:+-q}\n> > +\t\tif test $# != 0\n> > +\t\tthen\n> > +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> > +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n> \n> \"ls-files -z\" on the command line?  \n> \n> Apparently new tests do not cover the correctness of this codepath.\n> \n> I wonder if this\n> \n> \tgit ls-files -z --modified \"$@\" |\n> \tgit checkout-index -z --force --stdin\n> \n> is what the above \"checkout\" wanted to do.  The \"reset\" in the\n> previous step presumably updated the index entries that match\n> specified pathspec to those of the HEAD, so checking out the paths\n> that match \"$@\" from the index would be the same as checking them\n> out from the HEAD (while updating the index with them).\n\nYes, you're completely right, this is exactly what it should have\ndone.  Sorry for being slow on getting this right.\n\n> Perhaps squash the following into an appropriate patch in the\n> series?\n\nThanks, I'll squash this in and re-roll.\n\n>  git-stash.sh     |  3 ++-\n>  t/t3903-stash.sh | 16 ++++++++++++++++\n>  2 files changed, 18 insertions(+), 1 deletion(-)\n> \n> diff --git a/git-stash.sh b/git-stash.sh\n> index 28d0624c75..9c70662cc8 100755\n> --- a/git-stash.sh\n> +++ b/git-stash.sh\n> @@ -300,7 +300,8 @@ push_stash () {\n>  \t\tif test $# != 0\n>  \t\tthen\n>  \t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> -\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n> +\t\t\tgit ls-files -z --modified -- \"$@\" |\n> +\t\t\tgit checkout-index -z --force --stdin\n>  \t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n>  \t\telse\n>  \t\t\tgit reset --hard ${GIT_QUIET:+-q}\n> diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\n> index f7733b4dd4..e868aafab2 100755\n> --- a/t/t3903-stash.sh\n> +++ b/t/t3903-stash.sh\n> @@ -891,4 +891,20 @@ test_expect_success 'stash without verb with pathspec' '\n>  \ttest_path_is_file bar\n>  '\n>  \n> +test_expect_success 'stash with pathspec matching multiple paths' '\n> +\techo original >file &&\n> +\techo original >other-file &&\n> +\tgit commit -m \"two\" file other-file &&\n> +\techo modified >file &&\n> +\techo modified >other-file &&\n> +\tgit stash -- \"*file\" &&\n> +\techo original >expect &&\n> +\ttest_cmp expect file &&\n> +\ttest_cmp expect other-file &&\n> +\tgit stash pop &&\n> +\techo modified >expect &&\n> +\ttest_cmp expect file &&\n> +\ttest_cmp expect other-file\n> +'\n> +\n>  test_done\n"},{"id":"312785","messageId":"20170227215627.GB17065@hank","threadId":"45122","inReplyTo":"xmqq60jvwewc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-27T21:56:27Z","receivedAt":"2017-02-27T22:06:44Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/27, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > +\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n> \n> This silent \"exit 1\" made me scratch my head, but --error-unmatch\n> would have already given an error message, like\n> \n>     error: pathspec 'no such' did not match any file(s) known to git.\n>     Did you forget to 'git add'?\n> \n> so that would be OK.\n\nYeah exactly, the plan was to let --error-unmatch print the error\nmessage, as it's better at giving a good error message than we could\neasily do here I think.\n\nMaybe this deserves a comment so others won't have the same doubts\nabout this line?\n"},{"id":"312796","messageId":"xmqqa897wf1c.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170225213306.2410-5-t.gummerer@gmail.com","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T20:32:31Z","receivedAt":"2017-02-27T22:44:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n>  \tif test -z \"$patch_mode\"\n>  \tthen\n> -\t\tgit reset --hard ${GIT_QUIET:+-q}\n> +\t\tif test $# != 0\n> +\t\tthen\n> +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n\n\"ls-files -z\" on the command line?  \n\nApparently new tests do not cover the correctness of this codepath.\n\nI wonder if this\n\n\tgit ls-files -z --modified \"$@\" |\n\tgit checkout-index -z --stdin\n\nis what the above \"checkout\" wanted to do.  The \"reset\" in the\nprevious step presumably updated the index entries that match\nspecified pathspec to those of the HEAD, so checking out the paths\nthat match \"$@\" from the index would be the same as checking them\nout from the HEAD (while updating the index with them).\n\n> +\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n> +\t\telse\n> +\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n> +\t\tfi\n\nThanks.\n"},{"id":"312801","messageId":"xmqq8tormea6.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170227215627.GB17065@hank","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T22:58:57Z","receivedAt":"2017-02-27T23:28:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> On 02/27, Junio C Hamano wrote:\n>> Thomas Gummerer <t.gummerer@gmail.com> writes:\n>> \n>> > +\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n>> \n>> This silent \"exit 1\" made me scratch my head, but --error-unmatch\n>> would have already given an error message, like\n>> \n>>     error: pathspec 'no such' did not match any file(s) known to git.\n>>     Did you forget to 'git add'?\n>> \n>> so that would be OK.\n>\n> Yeah exactly, the plan was to let --error-unmatch print the error\n> message, as it's better at giving a good error message than we could\n> easily do here I think.\n>\n> Maybe this deserves a comment so others won't have the same doubts\n> about this line?\n\nNah, I do not think so.  It probably is obvious for those who write\n(and read) \"--error-unmatch\".  I was just being slow to realize that\nthe sole point of that option was to complain ;-)\n"},{"id":"312803","messageId":"xmqqwpcbuyrd.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170225213306.2410-5-t.gummerer@gmail.com","subject":"Re: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T21:09:26Z","receivedAt":"2017-02-27T23:51:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n>  \tif test -z \"$patch_mode\"\n>  \tthen\n> -\t\tgit reset --hard ${GIT_QUIET:+-q}\n> +\t\tif test $# != 0\n> +\t\tthen\n> +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n\n\"ls-files -z\" on the command line?  \n\nApparently new tests do not cover the correctness of this codepath.\n\nI wonder if this\n\n\tgit ls-files -z --modified \"$@\" |\n\tgit checkout-index -z --force --stdin\n\nis what the above \"checkout\" wanted to do.  The \"reset\" in the\nprevious step presumably updated the index entries that match\nspecified pathspec to those of the HEAD, so checking out the paths\nthat match \"$@\" from the index would be the same as checking them\nout from the HEAD (while updating the index with them).\n\nPerhaps squash the following into an appropriate patch in the\nseries?\n\n git-stash.sh     |  3 ++-\n t/t3903-stash.sh | 16 ++++++++++++++++\n 2 files changed, 18 insertions(+), 1 deletion(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 28d0624c75..9c70662cc8 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -300,7 +300,8 @@ push_stash () {\n \t\tif test $# != 0\n \t\tthen\n \t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n-\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n+\t\t\tgit ls-files -z --modified -- \"$@\" |\n+\t\t\tgit checkout-index -z --force --stdin\n \t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n \t\telse\n \t\t\tgit reset --hard ${GIT_QUIET:+-q}\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex f7733b4dd4..e868aafab2 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -891,4 +891,20 @@ test_expect_success 'stash without verb with pathspec' '\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash with pathspec matching multiple paths' '\n+\techo original >file &&\n+\techo original >other-file &&\n+\tgit commit -m \"two\" file other-file &&\n+\techo modified >file &&\n+\techo modified >other-file &&\n+\tgit stash -- \"*file\" &&\n+\techo original >expect &&\n+\ttest_cmp expect file &&\n+\ttest_cmp expect other-file &&\n+\tgit stash pop &&\n+\techo modified >expect &&\n+\ttest_cmp expect file &&\n+\ttest_cmp expect other-file\n+'\n+\n test_done\n"},{"id":"312882","messageId":"20170228203340.18723-4-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 3/6] stash: refactor stash_create","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:37Z","receivedAt":"2017-02-28T20:34:56Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Refactor the internal stash_create function to use a -m flag for\nspecifying the message and -u flag to indicate whether untracked files\nshould be added to the stash.\n\nThis makes it easier to pass a pathspec argument to stash_create in the\nnext patch.\n\nThe user interface for git stash create stays the same.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n git-stash.sh | 22 ++++++++++++++++++----\n 1 file changed, 18 insertions(+), 4 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8365ebba2a..ef5d1b45be 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -58,8 +58,22 @@ clear_stash () {\n }\n \n create_stash () {\n-\tstash_msg=\"$1\"\n-\tuntracked=\"$2\"\n+\tstash_msg=\n+\tuntracked=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\tstash_msg=${1?\"BUG: create_stash () -m requires an argument\"}\n+\t\t\t;;\n+\t\t-u|--include-untracked)\n+\t\t\tshift\n+\t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \n \tgit update-index -q --refresh\n \tif no_changes\n@@ -268,7 +282,7 @@ push_stash () {\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash \"$stash_msg\" $untracked\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n@@ -667,7 +681,7 @@ clear)\n \t;;\n create)\n \tshift\n-\tcreate_stash \"$*\" && echo \"$w_commit\"\n+\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n \t;;\n store)\n \tshift\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312884","messageId":"20170228203340.18723-7-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 6/6] stash: allow pathspecs in the no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:40Z","receivedAt":"2017-02-28T20:35:10Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that stash_push is used in the no verb form of stash, allow\nspecifying the command line for this form as well.  Always use -- to\ndisambiguate pathspecs from other non-option arguments.\n\nAlso make git stash -p an alias for git stash push -p.  This allows\nusers to use git stash -p <pathspec>.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt | 11 +++++++----\n git-stash.sh                |  3 +++\n t/t3903-stash.sh            | 15 +++++++++++++++\n 3 files changed, 25 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 4d8d30f179..70191d06b6 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -54,10 +54,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\n \tThe <message> part is optional and gives\n-\tthe description along with the stashed state.  For quickly making\n-\ta snapshot, you can omit _both_ \"save\" and <message>, but giving\n-\tonly <message> does not trigger this action to prevent a misspelled\n-\tsubcommand from making an unwanted stash.\n+\tthe description along with the stashed state.\n++\n+For quickly making a snapshot, you can omit \"push\".  In this mode,\n+non-option arguments are not allowed to prevent a misspelled\n+subcommand from making an unwanted stash.  The two exceptions to this\n+are `stash -p` which acts as alias for `stash push -p` and pathspecs,\n+which are allowed after a double hyphen `--` for disambiguation.\n +\n When pathspec is given to 'git stash push', the new stash records the\n modified states only for the files that match the pathspec.  The index\ndiff --git a/git-stash.sh b/git-stash.sh\nindex f3c2f86804..207c8126f4 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -657,12 +657,15 @@ apply_to_branch () {\n \t}\n }\n \n+test \"$1\" = \"-p\" && set \"push\" \"$@\"\n+\n PARSE_CACHE='--not-parsed'\n # The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n \tcase \"$opt\" in\n+\t--) break ;;\n \t-*) ;;\n \t*) seen_non_option=t; break ;;\n \tesac\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex e875fe8259..89877e4b52 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -892,4 +892,19 @@ test_expect_success 'untracked files are left in place when -u is not given' '\n \ttest_path_is_file untracked\n '\n \n+test_expect_success 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312885","messageId":"20170228203340.18723-2-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 1/6] stash: introduce push verb","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:35Z","receivedAt":"2017-02-28T20:35:11Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Introduce a new git stash push verb in addition to git stash save.  The\npush verb is used to transition from the current command line arguments\nto a more conventional way, in which the message is given as an argument\nto the -m option.\n\nThis allows us to have pathspecs at the end of the command line\narguments like other Git commands do, so that the user can say which\nsubset of paths to stash (and leave others behind).\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  3 +++\n git-stash.sh                | 46 ++++++++++++++++++++++++++++++++++++++++++---\n t/t3903-stash.sh            |  9 +++++++++\n 3 files changed, 55 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 2e9e344cd7..d240df4af7 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -15,6 +15,8 @@ SYNOPSIS\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n+'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -46,6 +48,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n \n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..8365ebba2a 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -9,6 +9,8 @@ USAGE=\"list [<options>]\n    or: $dashless branch <branchname> [<stash>]\n    or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n+   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -189,10 +191,11 @@ store_stash () {\n \treturn $ret\n }\n \n-save_stash () {\n+push_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tstash_msg=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +219,11 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t-m|--message)\n+\t\t\tshift\n+\t\t\ttest -z ${1+x} && usage\n+\t\t\tstash_msg=$1\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -251,8 +259,6 @@ save_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n-\tstash_msg=\"$*\"\n-\n \tgit update-index -q --refresh\n \tif no_changes\n \tthen\n@@ -291,6 +297,36 @@ save_stash () {\n \tfi\n }\n \n+save_stash () {\n+\tpush_options=\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\t# pass all options through to push_stash\n+\t\t\tpush_options=\"$push_options $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tstash_msg=\"$*\"\n+\n+\tif test -z \"$stash_msg\"\n+\tthen\n+\t\tpush_stash $push_options\n+\telse\n+\t\tpush_stash $push_options -m \"$stash_msg\"\n+\tfi\n+}\n+\n have_stash () {\n \tgit rev-parse --verify --quiet $ref_stash >/dev/null\n }\n@@ -617,6 +653,10 @@ save)\n \tshift\n \tsave_stash \"$@\"\n \t;;\n+push)\n+\tshift\n+\tpush_stash \"$@\"\n+\t;;\n apply)\n \tshift\n \tapply_stash \"$@\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 2de3e18ce6..3577115807 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,13 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'push -m shows right message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit stash push -m \"test message\" &&\n+\techo \"stash@{0}: On master: test message\" >expect &&\n+\tgit stash list -1 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312886","messageId":"20170228203340.18723-5-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:38Z","receivedAt":"2017-02-28T20:35:13Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"While working on a repository, it's often helpful to stash the changes\nof a single or multiple files, and leave others alone.  Unfortunately\ngit currently offers no such option.  git stash -p can be used to work\naround this, but it's often impractical when there are a lot of changes\nover multiple files.\n\nAllow 'git stash push' to take pathspec to specify which paths to stash.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt        |  9 +++-\n git-stash.sh                       | 39 +++++++++++-----\n t/t3903-stash.sh                   | 92 ++++++++++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh | 26 +++++++++++\n 4 files changed, 154 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex d240df4af7..88369ed8b6 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n \t     [-u|--include-untracked] [-a|--all] [<message>]]\n 'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n+\t     [--] [<pathspec>...]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\n@@ -48,7 +49,7 @@ OPTIONS\n -------\n \n save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::\n-push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::\n+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::\n \n \tSave your local modifications to a new 'stash' and roll them\n \tback to HEAD (in the working tree and in the index).\n@@ -58,6 +59,12 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q\n \tonly <message> does not trigger this action to prevent a misspelled\n \tsubcommand from making an unwanted stash.\n +\n+When pathspec is given to 'git stash push', the new stash records the\n+modified states only for the files that match the pathspec.  The index\n+entries and working tree files are then rolled back to the state in\n+HEAD only for these files, too, leaving files that do not match the\n+pathspec intact.\n++\n If the `--keep-index` option is used, all changes already added to the\n index are left intact.\n +\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ef5d1b45be..5892abafa3 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -11,6 +11,7 @@ USAGE=\"list [<options>]\n \t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n    or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t      [-- <pathspec>...]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -35,15 +36,15 @@ else\n fi\n \n no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- &&\n-\tgit diff-files --quiet --ignore-submodules &&\n+\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n+\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n \t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n }\n \n untracked_files () {\n \texcl_opt=--exclude-standard\n \ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt\n+\tgit ls-files -o -z $excl_opt -- \"$@\"\n }\n \n clear_stash () {\n@@ -71,12 +72,16 @@ create_stash () {\n \t\t\tshift\n \t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n \t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n \t\tesac\n \t\tshift\n \tdone\n \n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\texit 0\n \tfi\n@@ -108,7 +113,7 @@ create_stash () {\n \t\t# Untracked files are stored by themselves in a parentless commit, for\n \t\t# ease of unpacking later.\n \t\tu_commit=$(\n-\t\t\tuntracked_files | (\n+\t\t\tuntracked_files \"$@\" | (\n \t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\t\texport GIT_INDEX_FILE &&\n \t\t\t\trm -f \"$TMPindex\" &&\n@@ -131,7 +136,7 @@ create_stash () {\n \t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n \t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n \t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- >\"$TMP-stagenames\" &&\n+\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n \t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n \t\t\tgit write-tree &&\n \t\t\trm -f \"$TMPindex\"\n@@ -145,7 +150,7 @@ create_stash () {\n \n \t\t# find out what the user wants\n \t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- &&\n+\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -273,27 +278,39 @@ push_stash () {\n \t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n \tfi\n \n+\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n+\n \tgit update-index -q --refresh\n-\tif no_changes\n+\tif no_changes \"$@\"\n \tthen\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n \tfi\n+\n \tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\"\n+\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n \tstore_stash -m \"$stash_msg\" -q $w_commit ||\n \tdie \"$(gettext \"Cannot save the current status\")\"\n \tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tif test $# != 0\n+\t\tthen\n+\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n+\t\t\tgit ls-files -z --modified -- \"$@\" |\n+\t\t\tgit checkout-index -z --force --stdin\n+\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n+\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n+\t\telse\n+\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n+\t\tfi\n \t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n \t\tif test -n \"$untracked\"\n \t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION\n+\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex ffe3549ea5..f934993263 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -802,4 +802,96 @@ test_expect_success 'create with multiple arguments for the message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with multiple pathspec arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success 'stash with pathspec matching multiple paths' '\n+       echo original >file &&\n+       echo original >other-file &&\n+       git commit -m \"two\" file other-file &&\n+       echo modified >file &&\n+       echo modified >other-file &&\n+       git stash push -- \"*file\" &&\n+       echo original >expect &&\n+       test_cmp expect file &&\n+       test_cmp expect other-file &&\n+       git stash pop &&\n+       echo modified >expect &&\n+       test_cmp expect file &&\n+       test_cmp expect other-file\n+'\n+\n+test_expect_success 'stash push -p with pathspec shows no changes only once' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push -p foo >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec shows no changes when there are none' '\n+\t>foo &&\n+\tgit add foo &&\n+\tgit commit -m \"tmp\" &&\n+\tgit stash push foo >actual &&\n+\techo \"No local changes to save\" >expect &&\n+\tgit reset --hard HEAD~ &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'stash push with pathspec not in the repository errors out' '\n+\t>untracked &&\n+\ttest_must_fail git stash push untracked &&\n+\ttest_path_is_file untracked\n+'\n+\n+test_expect_success 'untracked files are left in place when -u is not given' '\n+\t>file &&\n+\tgit add file &&\n+\t>untracked &&\n+\tgit stash push file &&\n+\ttest_path_is_file untracked\n+'\n+\n test_done\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex f372fc8ca8..193adc7b68 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '\n \ttest -s .gitignore\n '\n \n+test_expect_success 'stash push --include-untracked with pathspec' '\n+\t>foo &&\n+\t>bar &&\n+\tgit stash push --include-untracked -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file foo\n+'\n+\n+test_expect_success 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_done\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312888","messageId":"20170228203340.18723-1-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170225213306.2410-1-t.gummerer@gmail.com","subject":"[PATCH v8 0/6] stash: support pathspec argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:34Z","receivedAt":"2017-02-28T20:35:33Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Thanks Junio for the review and the squashable diff with the fix for\nmy errors.\n\nI changed it a tiny bit, to use git stash push instead of git stash,\nso the complete diff could go into 4/6, where I think I think the test\nfits best.\n\nInterdiff below:\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 28d0624c75..207c8126f4 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -300,6 +300,8 @@ push_stash () {\n \t\tif test $# != 0\n \t\tthen\n \t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n+\t\t\tgit ls-files -z --modified -- \"$@\" |\n+\t\t\tgit checkout-index -z --force --stdin\n \t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n \t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n \t\telse\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex f7733b4dd4..89877e4b52 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -842,6 +842,22 @@ test_expect_success 'stash with file including $IFS character' '\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash with pathspec matching multiple paths' '\n+       echo original >file &&\n+       echo original >other-file &&\n+       git commit -m \"two\" file other-file &&\n+       echo modified >file &&\n+       echo modified >other-file &&\n+       git stash push -- \"*file\" &&\n+       echo original >expect &&\n+       test_cmp expect file &&\n+       test_cmp expect other-file &&\n+       git stash pop &&\n+       echo modified >expect &&\n+       test_cmp expect file &&\n+       test_cmp expect other-file\n+'\n+\n test_expect_success 'stash push -p with pathspec shows no changes only once' '\n \t>foo &&\n \tgit add foo &&\n\nThomas Gummerer (6):\n  stash: introduce push verb\n  stash: add test for the create command line arguments\n  stash: refactor stash_create\n  stash: teach 'push' (and 'create_stash') to honor pathspec\n  stash: use stash_push for no verb form\n  stash: allow pathspecs in the no verb form\n\n Documentation/git-stash.txt        |  25 +++++--\n git-stash.sh                       | 116 +++++++++++++++++++++++++------\n t/t3903-stash.sh                   | 138 ++++++++++++++++++++++++++++++++++++-\n t/t3905-stash-include-untracked.sh |  26 +++++++\n 4 files changed, 275 insertions(+), 30 deletions(-)\n\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312889","messageId":"20170228203340.18723-3-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 2/6] stash: add test for the create command line arguments","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:36Z","receivedAt":"2017-02-28T20:35:55Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently there is no test showing the expected behaviour of git stash\ncreate's command line arguments.  Add a test for that to show the\ncurrent expected behaviour and to make sure future refactorings don't\nbreak those expectations.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/t3903-stash.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 3577115807..ffe3549ea5 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -784,4 +784,22 @@ test_expect_success 'push -m shows right message' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'create stores correct message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create \"create test message\") &&\n+\techo \"On master: create test message\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'create with multiple arguments for the message' '\n+\t>foo &&\n+\tgit add foo &&\n+\tSTASH_ID=$(git stash create test untracked) &&\n+\techo \"On master: test untracked\" >expect &&\n+\tgit show --pretty=%s -s ${STASH_ID} >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312890","messageId":"20170228203340.18723-6-t.gummerer@gmail.com","threadId":"45122","inReplyTo":"20170228203340.18723-1-t.gummerer@gmail.com","subject":"[PATCH v8 5/6] stash: use stash_push for no verb form","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-02-28T20:33:39Z","receivedAt":"2017-02-28T20:36:45Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have stash_push, which accepts pathspec arguments, use\nit instead of stash_save in git stash without any additional verbs.\n\nPreviously we allowed git stash -- -message, which is no longer allowed\nafter this patch.  Messages starting with a hyphen was allowed since\n3c2eb80f, (\"stash: simplify defaulting to \"save\" and reject unknown\noptions\").  However it was never the intent to allow that, but rather it\nwas allowed accidentally.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-stash.txt |  8 ++++----\n git-stash.sh                | 16 ++++++++--------\n t/t3903-stash.sh            |  4 +---\n 3 files changed, 13 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 88369ed8b6..4d8d30f179 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -13,11 +13,11 @@ SYNOPSIS\n 'git stash' drop [-q|--quiet] [<stash>]\n 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n 'git stash' branch <branchname> [<stash>]\n-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t     [-u|--include-untracked] [-a|--all] [<message>]]\n-'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t     [-u|--include-untracked] [-a|--all] [<message>]\n+'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n \t     [-u|--include-untracked] [-a|--all] [-m|--message <message>]]\n-\t     [--] [<pathspec>...]\n+\t     [--] [<pathspec>...]]\n 'git stash' clear\n 'git stash' create [<message>]\n 'git stash' store [-m|--message <message>] [-q|--quiet] <commit>\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 5892abafa3..f3c2f86804 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -7,11 +7,11 @@ USAGE=\"list [<options>]\n    or: $dashless drop [-q|--quiet] [<stash>]\n    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n    or: $dashless branch <branchname> [<stash>]\n-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [<message>]]\n-   or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t      [-- <pathspec>...]\n+   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n+   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n+\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n+\t\t       [-- <pathspec>...]]\n    or: $dashless clear\"\n \n SUBDIRECTORY_OK=Yes\n@@ -658,7 +658,7 @@ apply_to_branch () {\n }\n \n PARSE_CACHE='--not-parsed'\n-# The default command is \"save\" if nothing but options are given\n+# The default command is \"push\" if nothing but options are given\n seen_non_option=\n for opt\n do\n@@ -668,7 +668,7 @@ do\n \tesac\n done\n \n-test -n \"$seen_non_option\" || set \"save\" \"$@\"\n+test -n \"$seen_non_option\" || set \"push\" \"$@\"\n \n # Main command set\n case \"$1\" in\n@@ -719,7 +719,7 @@ branch)\n *)\n \tcase $# in\n \t0)\n-\t\tsave_stash &&\n+\t\tpush_stash &&\n \t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n \t\t;;\n \t*)\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex f934993263..e875fe8259 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' '\n \tgit add file2 &&\n \ttest_must_fail git stash --invalid-option &&\n \ttest_must_fail git stash save --invalid-option &&\n-\ttest bar5,bar6 = $(cat file),$(cat file2) &&\n-\tgit stash -- -message-starting-with-dash &&\n-\ttest bar,bar2 = $(cat file),$(cat file2)\n+\ttest bar5,bar6 = $(cat file),$(cat file2)\n '\n \n test_expect_success 'stash an added file' '\n-- \n2.12.0.428.g67fe103aa\n\n"},{"id":"312914","messageId":"xmqqo9xmhshd.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170228203340.18723-5-t.gummerer@gmail.com","subject":"Re: [PATCH v8 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-28T22:15:42Z","receivedAt":"2017-02-28T22:15:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> +\t\t\tgit ls-files -z --modified -- \"$@\" |\n> +\t\t\tgit checkout-index -z --force --stdin\n> +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n\nI think you forgot to remove this line, whose correction was added\nas two lines immediately before it.  I'll remove it while queuing.\n\n> +\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n\nThanks.\n"},{"id":"312990","messageId":"xmqqtw7cehzb.fsf@gitster.mtv.corp.google.com","threadId":"45122","inReplyTo":"20170301215759.GA11067@hank","subject":"Re: [PATCH v8 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-01T22:43:04Z","receivedAt":"2017-03-01T22:43:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> On 02/28, Junio C Hamano wrote:\n>> Thomas Gummerer <t.gummerer@gmail.com> writes:\n>> \n>> > +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n>> > +\t\t\tgit ls-files -z --modified -- \"$@\" |\n>> > +\t\t\tgit checkout-index -z --force --stdin\n>> > +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n>> \n>> I think you forgot to remove this line, whose correction was added\n>> as two lines immediately before it.  I'll remove it while queuing.\n>\n> Yes, sorry.  What you queued looks good to me, thanks!\n\nThanks for double-checking, and thanks for working on the topic.  I\nthink this is ready for 'next'.\n"},{"id":"312996","messageId":"20170301215759.GA11067@hank","threadId":"45122","inReplyTo":"xmqqo9xmhshd.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-03-01T21:57:59Z","receivedAt":"2017-03-01T22:59:03Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 02/28, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > +\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n> > +\t\t\tgit ls-files -z --modified -- \"$@\" |\n> > +\t\t\tgit checkout-index -z --force --stdin\n> > +\t\t\tgit checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified \"$@\")\n> \n> I think you forgot to remove this line, whose correction was added\n> as two lines immediately before it.  I'll remove it while queuing.\n\nYes, sorry.  What you queued looks good to me, thanks!\n\n> > +\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n> \n> Thanks.\n"}]}