{"thread":{"id":"44884","subject":"[RFC] stash: support filename argument","startedAt":"2017-01-15T14:25:45Z","lastAt":"2017-01-16T23:49:33Z","messageCount":8,"participants":["Thomas Gummerer","Junio C Hamano","Stephan Beyer","Marc Strapetz","Johannes Schindelin","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"309438","messageId":"20170115142542.11999-1-t.gummerer@gmail.com","threadId":"44884","inReplyTo":null,"subject":"[RFC] stash: support filename argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-01-15T14:25:42Z","receivedAt":"2017-01-15T14:25:45Z","isPatch":false,"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\nAdd a --file option to git stash save, which allows for stashing a\nsingle file.  Specifying the --file argument multiple times allows\nstashing more than one file at a time.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nMarked as RFC and without documentation updates to first get a feeling\nfor the user interface, and whether people are interested in this\nchange.\n\nIdeally I wanted the the user interface to look like something like:\ngit stash save -- [<filename1,...>], but unfortunately that's already\ntaken up by the stash message.  So to preserve backward compatibility\nI used the new --file argument.\n\n git-stash.sh     | 45 +++++++++++++++++++++++++++++++++++++--------\n t/t3903-stash.sh | 27 +++++++++++++++++++++++++++\n 2 files changed, 64 insertions(+), 8 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 10c284d1aa..0ef1b5b56e 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -41,7 +41,7 @@ no_changes () {\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 -- $1\n }\n \n clear_stash () {\n@@ -56,6 +56,23 @@ clear_stash () {\n }\n \n create_stash () {\n+\tfiles=\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--files)\n+\t\t\t;;\n+\t\t*)\n+\t\t\tfiles=\"$1 $files\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n \tstash_msg=\"$1\"\n \tuntracked=\"$2\"\n \n@@ -92,7 +109,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 $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@@ -115,7 +132,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 -- $files >\"$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@@ -129,7 +146,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 -- $files &&\n \n \t\t# state of the working tree\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n@@ -193,6 +210,7 @@ save_stash () {\n \tkeep_index=\n \tpatch_mode=\n \tuntracked=\n+\tfiles=\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -216,6 +234,10 @@ save_stash () {\n \t\t-a|--all)\n \t\t\tuntracked=all\n \t\t\t;;\n+\t\t--file)\n+\t\t\tshift\n+\t\t\tfiles=\"$files $1\"\n+\t\t\t;;\n \t\t--help)\n \t\t\tshow_help\n \t\t\t;;\n@@ -262,18 +284,25 @@ save_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 --files $files -- \"$stash_msg\" \"$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 -n \"$files\"\n+\t\tthen\n+\t\t\tgit reset -- $files\n+\t\t\tgit checkout HEAD -- $(git ls-files --modified -- $files)\n+\t\t\tgit clean --force --quiet -- $(git ls-files --others -- $files)\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 -- $files\n \t\tfi\n \n \t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\n@@ -627,7 +656,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 2de3e18ce6..42bfca873b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -775,4 +775,31 @@ test_expect_success 'stash is not confused by partial renames' '\n \ttest_path_is_missing file\n '\n \n+test_expect_success 'stash --file <filename> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash save --file 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 &&\n+\tgit stash save --file foo --file 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_done\n-- \n2.11.0.258.ge05806da9e.dirty\n\n"},{"id":"309460","messageId":"xmqqvatfc0rt.fsf@gitster.mtv.corp.google.com","threadId":"44884","inReplyTo":"20170115142542.11999-1-t.gummerer@gmail.com","subject":"Re: [RFC] stash: support filename argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-01-16T00:21:42Z","receivedAt":"2017-01-16T00:21:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> While working on a repository, it's often helpful to stash the changes\n> of a single or multiple files, and leave others alone.  Unfortunately\n> git currently offers no such option.  git stash -p can be used to work\n> around this, but it's often impractical when there are a lot of changes\n> over multiple files.\n>\n> Add a --file option to git stash save, which allows for stashing a\n> single file.  Specifying the --file argument multiple times allows\n> stashing more than one file at a time.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>\n> Marked as RFC and without documentation updates to first get a feeling\n> for the user interface, and whether people are interested in this\n> change.\n>\n> Ideally I wanted the the user interface to look like something like:\n> git stash save -- [<filename1,...>], but unfortunately that's already\n> taken up by the stash message.  So to preserve backward compatibility\n> I used the new --file argument.\n\nI haven't spent enough time to think if it even makes sense to\n\"stash\" partially, leaving the working tree still dirty.  My initial\nreaction was \"then stashing away the dirty WIP state to get a spiffy\nclean working environment becomes impossible\", and I still need time\nto recover from that ;-)  So as to the desirablity of this \"feature\",\nI have no strong opinion for or against yet.\n\nBut if we were to do this, then we should bite the bullet and\ndeclare that \"stash save <message>\" was a mistake.  It should have\nbeen \"stash save -m <message>\" and we should transition to that (one\neasy way out would be to find another verb that is not 'save').\n\nThen we can do \"git stash save [-m <msg>] [--] [pathspec...]\" which\nfollows the usual command line convention.\n"},{"id":"309463","messageId":"c0d46a97-b1c0-d9c9-e475-28e0368ac61f@gmx.net","threadId":"44884","inReplyTo":"xmqqvatfc0rt.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC] stash: support filename argument","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2017-01-16T00:41:02Z","receivedAt":"2017-01-16T00:41:19Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nOn 01/16/2017 01:21 AM, Junio C Hamano wrote:\n> I haven't spent enough time to think if it even makes sense to\n> \"stash\" partially, leaving the working tree still dirty.  My initial\n> reaction was \"then stashing away the dirty WIP state to get a spiffy\n> clean working environment becomes impossible\", and I still need time\n> to recover from that ;-)  So as to the desirablity of this \"feature\",\n> I have no strong opinion for or against yet.\nI do remember that I simulated that feature a few times (either by\nadding the to-be-keep stuff (hunks, not only files) to the index and use\n--keep-index, and sometimes by making a temporary commit (to make sure\nto not lose anything) and then stash). So I think there is a valid\ndesire of the feature.\n\nHowever, going further, the next feature to be requested could be \"git\nstash --patch\" ;D This leads me to think that the mentioned simulation\nof partial stashes might be something everyone might come up with who\nhas basic understanding of git features and \"git stash\", and might be\nthe more flexible and probably better solution to the problem.\n\nBest\n  Stephan\n"},{"id":"309476","messageId":"c8c5b5e1-b1f1-5b02-dc5f-0ec65f1a11a0@syntevo.com","threadId":"44884","inReplyTo":"c0d46a97-b1c0-d9c9-e475-28e0368ac61f@gmx.net","subject":"Re: [RFC] stash: support filename argument","fromName":"Marc Strapetz","fromEmail":"marc.strapetz@syntevo.com","sentAt":"2017-01-16T08:18:26Z","receivedAt":"2017-01-16T08:18:24Z","isPatch":false,"sender":{"key":"marc.strapetz@syntevo.com","avatar":"https://avatars.githubusercontent.com/u/3380730?v=4"},"body":"On 16.01.2017 01:41, Stephan Beyer wrote:\n> Hi,\n>\n> On 01/16/2017 01:21 AM, Junio C Hamano wrote:\n>> I haven't spent enough time to think if it even makes sense to\n>> \"stash\" partially, leaving the working tree still dirty.  My initial\n>> reaction was \"then stashing away the dirty WIP state to get a spiffy\n>> clean working environment becomes impossible\", and I still need time\n>> to recover from that ;-)  So as to the desirablity of this \"feature\",\n>> I have no strong opinion for or against yet.\n> I do remember that I simulated that feature a few times (either by\n> adding the to-be-keep stuff (hunks, not only files) to the index and use\n> --keep-index, and sometimes by making a temporary commit (to make sure\n> to not lose anything) and then stash). So I think there is a valid\n> desire of the feature.\n\nI can confirm this from a GUI client perspective, for which this feature \nmakes probably even more sense than for command line. It has been \nrequested by our users quite often compared to other features and \ncompared to \"git stash -p\" support.\n\n-Marc\n\n\n\n"},{"id":"309479","messageId":"alpine.DEB.2.20.1701161150320.3469@virtualbox","threadId":"44884","inReplyTo":"xmqqvatfc0rt.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC] stash: support filename argument","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-01-16T10:51:20Z","receivedAt":"2017-01-16T10:51:37Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 15 Jan 2017, Junio C Hamano wrote:\n\n> I haven't spent enough time to think if it even makes sense to\n> \"stash\" partially, leaving the working tree still dirty.\n\nThink no more! We already support that with --keep-index, and it is a very\nuseful feature.\n\nCiao,\nJohannes\n"},{"id":"309485","messageId":"alpine.DEB.2.20.1701161413400.3469@virtualbox","threadId":"44884","inReplyTo":"alpine.DEB.2.20.1701161150320.3469@virtualbox","subject":"Re: [RFC] stash: support filename argument","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-01-16T13:14:36Z","receivedAt":"2017-01-16T13:14:57Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 16 Jan 2017, Johannes Schindelin wrote:\n\n> On Sun, 15 Jan 2017, Junio C Hamano wrote:\n> \n> > I haven't spent enough time to think if it even makes sense to\n> > \"stash\" partially, leaving the working tree still dirty.\n> \n> Think no more! We already support that with --keep-index, and it is a very\n> useful feature.\n\nAnd of course there is `git stash -p`, which is also very useful,\n*because* it leaves the working tree still dirty, in the desired way.\n\nCiao,\nJohannes\n"},{"id":"309502","messageId":"20170116222927.GA31189@hank","threadId":"44884","inReplyTo":"xmqqvatfc0rt.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC] stash: support filename argument","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2017-01-16T22:29:27Z","receivedAt":"2017-01-16T22:29:26Z","isPatch":false,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 01/15, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > While working on a repository, it's often helpful to stash the changes\n> > of a single or multiple files, and leave others alone.  Unfortunately\n> > git currently offers no such option.  git stash -p can be used to work\n> > around this, but it's often impractical when there are a lot of changes\n> > over multiple files.\n> >\n> > Add a --file option to git stash save, which allows for stashing a\n> > single file.  Specifying the --file argument multiple times allows\n> > stashing more than one file at a time.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >\n> > Marked as RFC and without documentation updates to first get a feeling\n> > for the user interface, and whether people are interested in this\n> > change.\n> >\n> > Ideally I wanted the the user interface to look like something like:\n> > git stash save -- [<filename1,...>], but unfortunately that's already\n> > taken up by the stash message.  So to preserve backward compatibility\n> > I used the new --file argument.\n> \n> I haven't spent enough time to think if it even makes sense to\n> \"stash\" partially, leaving the working tree still dirty.  My initial\n> reaction was \"then stashing away the dirty WIP state to get a spiffy\n> clean working environment becomes impossible\", and I still need time\n> to recover from that ;-)  So as to the desirablity of this \"feature\",\n> I have no strong opinion for or against yet.\n\nAs others mentioned, this would be similar to stash -p.  My main\nusecase is stashing away a config file or changes in one test file\nwhile I forget to test something without these changes.  I definitely\nused git stash -p on more than one occasion to simulate this behaviour\nbefore.\n\n> But if we were to do this, then we should bite the bullet and\n> declare that \"stash save <message>\" was a mistake.  It should have\n> been \"stash save -m <message>\" and we should transition to that (one\n> easy way out would be to find another verb that is not 'save').\n>\n> Then we can do \"git stash save [-m <msg>] [--] [pathspec...]\" which\n> follows the usual command line convention.\n\nI like this interface much better than the one in my patch.  I'm not\nsure about the verb we could use for the transition, maybe 'push'.  If\nanyone can come up with a different suggestion I'd be happy to hear\nit, as I'm not very good at naming things.\n\n-- \nThomas\n"},{"id":"309507","messageId":"20170116234924.72aeqo6ltrgov54o@sigill.intra.peff.net","threadId":"44884","inReplyTo":"c0d46a97-b1c0-d9c9-e475-28e0368ac61f@gmx.net","subject":"Re: [RFC] stash: support filename argument","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-16T23:49:25Z","receivedAt":"2017-01-16T23:49:33Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 16, 2017 at 01:41:02AM +0100, Stephan Beyer wrote:\n\n> However, going further, the next feature to be requested could be \"git\n> stash --patch\" ;D This leads me to think that the mentioned simulation\n> of partial stashes might be something everyone might come up with who\n> has basic understanding of git features and \"git stash\", and might be\n> the more flexible and probably better solution to the problem.\n\nDon't we have \"git stash -p\" already?[1]\n\nI use it all the time, and it's very handy for picking apart changes. I\nhave often wanted \"git stash -p <paths>\" to work, though.\n\n-Peff\n\n[1] I had to double check that it was not something I hacked together\n    locally and forgot about. :) It's from dda1f2a5c (Implement 'git\n    stash save --patch', 2009-08-13). I also worked up a \"git stash\n    apply -p\", but I remember it was buggy, and I haven't looked at it\n    in years. It's at:\n\n      https://github.com/peff/git/commit/2c4ed43987b20cfb1605fbd7648d81e454c45c71\n\n    if anybody is curious. I don't even recall what the problems were at\n    this point.\n"}]}