{"thread":{"id":"8805","subject":"[PATCH] Teach git-stash to \"apply --index\"","startedAt":"2007-07-02T11:14:49Z","lastAt":"2007-07-03T11:17:05Z","messageCount":3,"participants":["Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"46224","messageId":"Pine.LNX.4.64.0707021213350.4438@racer.site","threadId":"8805","inReplyTo":null,"subject":"[PATCH] Teach git-stash to \"apply --index\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-02T11:14:49Z","receivedAt":"2007-07-02T11:14:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen given this subcommand, git-stash will try to merge the stashed\nindex into the current one. Only trivial merges are possible, since\nwe have no index for the index ;-) If a trivial merge is not possible,\ngit-stash will bail out with a hint to skip the --index option.\n\nFor good measure, finally include a test case.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n\tI am not quite sure if this should not be the default, with\n\t--skip-index to turn it off if the trivial index merge fails,\n\tand the user might be interested only in the working directory\n\tchanges anyway.\n\n\tComments?\n\n git-stash.sh     |   21 ++++++++++++++++\n t/t3903-stash.sh |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 89 insertions(+), 1 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 04ce30a..45ad2f4 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -98,6 +98,13 @@ apply_stash () {\n \tgit-diff-files --quiet ||\n \t\tdie 'Cannot restore on top of a dirty state'\n \n+\tunstash_index=\n+\tcase \"$1\" in\n+\t--index)\n+\t\tunstash_index=t\n+\t\tshift\n+\tesac\n+\n \t# current index state\n \tc_tree=$(git-write-tree) ||\n \t\tdie 'Cannot apply a stash in the middle of a merge'\n@@ -107,6 +114,15 @@ apply_stash () {\n \tb_tree=$(git-rev-parse --verify \"$s^:\") ||\n \t\tdie \"$*: no valid stashed state found\"\n \n+\ttest -z \"$unstash_index\" || {\n+\t\tgit diff --binary $s^2^..$s^2 | git apply --cached\n+\t\ttest $? -ne 0 &&\n+\t\t\tdie 'Conflicts in index. Try without --index.'\n+\t\tunstashed_index_tree=$(git-write-tree) ||\n+\t\t\tdie 'Could not save index tree'\n+\t\tgit reset\n+\t}\n+\n \teval \"\n \t\tGITHEAD_$w_tree='Stashed changes' &&\n \t\tGITHEAD_$c_tree='Updated upstream' &&\n@@ -124,9 +140,12 @@ apply_stash () {\n \t\t\tdie \"Cannot unstage modified files\"\n \t\tgit-status\n \t\trm -f \"$a\"\n+\t\ttest -z \"$unstash_index\" || git read-tree $unstashed_index_tree\n \telse\n \t\t# Merge conflict; keep the exit status from merge-recursive\n-\t\texit\n+\t\tstatus=$?\n+\t\ttest -z \"$unstash_index\" || echo 'Index was not unstashed.' >&2\n+\t\texit $status\n \tfi\n }\n \ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nnew file mode 100755\nindex 0000000..392ac1c\n--- /dev/null\n+++ b/t/t3903-stash.sh\n@@ -0,0 +1,69 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2007 Johannes E Schindelin\n+#\n+\n+test_description='Test git-stash'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'stash some dirty working directory' '\n+\techo 1 > file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m initial &&\n+\techo 2 > file &&\n+\tgit add file &&\n+\techo 3 > file &&\n+\ttest_tick &&\n+\tgit stash &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --cached --quiet HEAD\n+'\n+\n+cat > expect << EOF\n+diff --git a/file b/file\n+index 0cfbf08..00750ed 100644\n+--- a/file\n++++ b/file\n+@@ -1 +1 @@\n+-2\n++3\n+EOF\n+\n+test_expect_success 'parents of stash' '\n+\ttest $(git rev-parse stash^) = $(git rev-parse HEAD) &&\n+\tgit diff stash^2..stash > output &&\n+\tdiff -u output expect\n+'\n+\n+test_expect_success 'apply needs clean working directory' '\n+\techo 4 > other-file &&\n+\tgit add other-file &&\n+\techo 5 > other-file\n+\t! git stash apply\n+'\n+\n+test_expect_success 'apply stashed changes' '\n+\tgit add other-file &&\n+\ttest_tick &&\n+\tgit commit -m other-file &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 1 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n+test_expect_success 'apply stashed changes (including index)' '\n+\tgit reset --hard HEAD^ &&\n+\techo 6 > other-file &&\n+\tgit add other-file &&\n+\ttest_tick &&\n+\tgit commit -m other-file &&\n+\tgit stash apply --index &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n+test_done\n"},{"id":"46324","messageId":"7vodiut8c3.fsf@assigned-by-dhcp.cox.net","threadId":"8805","inReplyTo":"Pine.LNX.4.64.0707021213350.4438@racer.site","subject":"Re: [PATCH] Teach git-stash to \"apply --index\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-03T04:33:16Z","receivedAt":"2007-07-03T04:33:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> \tI am not quite sure if this should not be the default, with\n> \t--skip-index to turn it off if the trivial index merge fails,\n> \tand the user might be interested only in the working directory\n> \tchanges anyway.\n>\n> \tComments?\n\nThere is a bit of impedance mismatch between a rename-aware\nthree-way merge (aka merge-recursive) used to update the working\ntree and a patch that updates the index.  The \"rename-aware\"\nthing can be fixed by doing the diff with -M, though.\n\nIt might be easier to explain (1) not have --index option, but\nattempt to do this always, and (2) even if the index cannot be\nupdated, keep going, without worrying about losing the\ndifference between I and W, probably with a message to the end\nuser.\n\nSuppose you are the user who gets \"perhaps you would want to run\nwithout --index?\" hint.  What can you do?  Run without --index,\nor forget about unstashing.  But the latter does not sound like\nan option.  So it feels to me that --index is an unnecessary\noption.\n\nThe potential confusion problem I mentioned in two of my earlier\nmessages due to the program doing one thing sometimes and\nanother thing some other times still applies, though.\n"},{"id":"46346","messageId":"Pine.LNX.4.64.0707031212570.4071@racer.site","threadId":"8805","inReplyTo":"7vodiut8c3.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Teach git-stash to \"apply --index\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-03T11:17:05Z","receivedAt":"2007-07-03T11:17:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 2 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > \tI am not quite sure if this should not be the default, with\n> > \t--skip-index to turn it off if the trivial index merge fails,\n> > \tand the user might be interested only in the working directory\n> > \tchanges anyway.\n> >\n> > \tComments?\n> \n> There is a bit of impedance mismatch between a rename-aware\n> three-way merge (aka merge-recursive) used to update the working\n> tree and a patch that updates the index.  The \"rename-aware\"\n> thing can be fixed by doing the diff with -M, though.\n\nAh yes, I did not think about renames. But like you said, adding -M to the \ndiff should help that.\n\n> It might be easier to explain (1) not have --index option, but attempt \n> to do this always, and (2) even if the index cannot be updated, keep \n> going, without worrying about losing the difference between I and W, \n> probably with a message to the end user.\n\nOkay, in this case I propose to make this the default, with an option \n\"--skip-index\" to only try re-apply the changes to the working directory.\n\n> Suppose you are the user who gets \"perhaps you would want to run without \n> --index?\" hint.  What can you do?  Run without --index, or forget about \n> unstashing.  But the latter does not sound like an option.  So it feels \n> to me that --index is an unnecessary option.\n\nIt is very much like the choice you have with \"git checkout\" vs \"git \ncheckout -f\". Either you change your index accordingly, or you say \"I \ndon't care about the index. What changes I had there, I will reconstruct \nmyself.\"\n\n> The potential confusion problem I mentioned in two of my earlier \n> messages due to the program doing one thing sometimes and another thing \n> some other times still applies, though.\n\nYes, that's why I would suggest not going ahead when the index could not \nbe easily merged. Rather give the user enough information to decide.\n\nOf course, this means that in complicated cases, the user mustn't run and \nhide when she hears \"index!\", but I guess that complicated cases always \nneed you to know your tools better than easy problems.\n\nCiao,\nDscho\n"}]}