{"thread":{"id":"29273","subject":"[PATCHv2] stash: Don't fail if work dir contains file named 'HEAD'","startedAt":"2011-12-31T00:14:01Z","lastAt":"2012-01-03T18:45:55Z","messageCount":2,"participants":["Jonathon Mah","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"181812","messageId":"A244F415-73A1-4A77-BC4A-AC7F85946F02@JonathonMah.com","threadId":"29273","inReplyTo":null,"subject":"[PATCHv2] stash: Don't fail if work dir contains file named 'HEAD'","fromName":"Jonathon Mah","fromEmail":"me@jonathonmah.com","sentAt":"2011-12-31T00:14:01Z","receivedAt":"2011-12-31T00:14:01Z","isPatch":false,"sender":{"key":"me@jonathonmah.com","avatar":"https://avatars.githubusercontent.com/u/2748?v=4"},"body":"When performing a plain \"git stash\" (without --patch), git-diff would fail\nwith \"fatal: ambiguous argument 'HEAD': both revision and filename\". The\noutput was piped into git-update-index, masking the failed exit status.\nThe output is now sent to a temporary file (which is cleaned up by\nexisting code), and the exit status is checked. The \"HEAD\" arg to the\ngit-diff invocation has been disambiguated too, of course.\n\nIn patch mode, \"git stash -p\" would fail harmlessly, leaving the working\ndir untouched. Interactive adding is fine, but the resulting tree was\ndiffed with an ambiguous 'HEAD' argument.\n\nUse >foo (no space) when redirecting output.\n\nIn t3904, checks and operations on each file are in the order they'll\nappear when interactively staging.\n\nIn t3905, fix a bug in \"stash save --include-untracked -q is quiet\": The\nredirected stdout file was considered untracked, and so was removed from\nthe working directory. Use test path helper functions where appropriate.\n\nSigned-off-by: Jonathon Mah <me@JonathonMah.com>\nAcked-by: Thomas Rast <trast@student.ethz.ch>\n---\nAlso contains several fixes / changes for tests. Let me know if these\nwould better belong separately.\n\n git-stash.sh                       |    7 +++--\n t/t3903-stash.sh                   |   24 ++++++++++++++++++\n t/t3904-stash-patch.sh             |   47 ++++++++++++++++++++++-------------\n t/t3905-stash-include-untracked.sh |   33 +++++++++++++++++-------\n 4 files changed, 80 insertions(+), 31 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex c766692..fe4ab28 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -115,7 +115,8 @@ 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 --name-only -z HEAD | git update-index -z --add --remove --stdin &&\n+\t\t\tgit diff --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 \t\t) ) ||\n@@ -134,7 +135,7 @@ create_stash () {\n \t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n \t\tdie \"$(gettext \"Cannot save the current worktree state\")\"\n \n-\t\tgit diff-tree -p HEAD $w_tree > \"$TMP-patch\" &&\n+\t\tgit diff-tree -p HEAD $w_tree -- >\"$TMP-patch\" &&\n \t\ttest -s \"$TMP-patch\" ||\n \t\tdie \"$(gettext \"No changes selected\")\"\n \n@@ -491,7 +492,7 @@ drop_stash () {\n \t\tdie \"$(eval_gettext \"\\${REV}: Could not drop stash entry\")\"\n \n \t# clear_stash if we just dropped the last stash entry\n-\tgit rev-parse --verify \"$ref_stash@{0}\" > /dev/null 2>&1 || clear_stash\n+\tgit rev-parse --verify \"$ref_stash@{0}\" >/dev/null 2>&1 || clear_stash\n }\n \n apply_to_branch () {\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex fcdb182..dbe2ac1 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -601,4 +601,28 @@ test_expect_success 'stash apply shows status same as git status (relative to cu\n \ttest_cmp expect actual\n '\n \n+cat > expect << EOF\n+diff --git a/HEAD b/HEAD\n+new file mode 100644\n+index 0000000..fe0cbee\n+--- /dev/null\n++++ b/HEAD\n+@@ -0,0 +1 @@\n++file-not-a-ref\n+EOF\n+\n+test_expect_success 'stash where working directory contains \"HEAD\" file' '\n+\tgit stash clear &&\n+\tgit reset --hard &&\n+\techo file-not-a-ref > HEAD &&\n+\tgit add HEAD &&\n+\ttest_tick &&\n+\tgit stash &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --cached --quiet HEAD &&\n+\ttest \"$(git rev-parse stash^)\" = \"$(git rev-parse HEAD)\" &&\n+\tgit diff stash^..stash > output &&\n+\ttest_cmp output expect\n+'\n+\n test_done\ndiff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh\nindex 781fd71..70655c1 100755\n--- a/t/t3904-stash-patch.sh\n+++ b/t/t3904-stash-patch.sh\n@@ -7,7 +7,8 @@ test_expect_success PERL 'setup' '\n \tmkdir dir &&\n \techo parent > dir/foo &&\n \techo dummy > bar &&\n-\tgit add bar dir/foo &&\n+\techo committed > HEAD &&\n+\tgit add bar dir/foo HEAD &&\n \tgit commit -m initial &&\n \ttest_tick &&\n \ttest_commit second dir/foo head &&\n@@ -17,47 +18,57 @@ test_expect_success PERL 'setup' '\n \tsave_head\n '\n \n-# note: bar sorts before dir, so the first 'n' is always to skip 'bar'\n+# note: order of files with unstaged changes: HEAD bar dir/foo\n \n test_expect_success PERL 'saying \"n\" does nothing' '\n+\tset_state HEAD HEADfile_work HEADfile_index &&\n \tset_state dir/foo work index &&\n-\t(echo n; echo n) | test_must_fail git stash save -p &&\n-\tverify_state dir/foo work index &&\n-\tverify_saved_state bar\n+\t(echo n; echo n; echo n) | test_must_fail git stash save -p &&\n+\tverify_state HEAD HEADfile_work HEADfile_index &&\n+\tverify_saved_state bar &&\n+\tverify_state dir/foo work index\n '\n \n test_expect_success PERL 'git stash -p' '\n-\t(echo n; echo y) | git stash save -p &&\n-\tverify_state dir/foo head index &&\n+\t(echo y; echo n; echo y) | git stash save -p &&\n+\tverify_state HEAD committed HEADfile_index &&\n \tverify_saved_state bar &&\n+\tverify_state dir/foo head index &&\n \tgit reset --hard &&\n \tgit stash apply &&\n-\tverify_state dir/foo work head &&\n-\tverify_state bar dummy dummy\n+\tverify_state HEAD HEADfile_work committed &&\n+\tverify_state bar dummy dummy &&\n+\tverify_state dir/foo work head\n '\n \n test_expect_success PERL 'git stash -p --no-keep-index' '\n-\tset_state dir/foo work index &&\n+\tset_state HEAD HEADfile_work HEADfile_index &&\n \tset_state bar bar_work bar_index &&\n-\t(echo n; echo y) | git stash save -p --no-keep-index &&\n-\tverify_state dir/foo head head &&\n+\tset_state dir/foo work index &&\n+\t(echo y; echo n; echo y) | git stash save -p --no-keep-index &&\n+\tverify_state HEAD committed committed &&\n \tverify_state bar bar_work dummy &&\n+\tverify_state dir/foo head head &&\n \tgit reset --hard &&\n \tgit stash apply --index &&\n-\tverify_state dir/foo work index &&\n-\tverify_state bar dummy bar_index\n+\tverify_state HEAD HEADfile_work HEADfile_index &&\n+\tverify_state bar dummy bar_index &&\n+\tverify_state dir/foo work index\n '\n \n test_expect_success PERL 'git stash --no-keep-index -p' '\n-\tset_state dir/foo work index &&\n+\tset_state HEAD HEADfile_work HEADfile_index &&\n \tset_state bar bar_work bar_index &&\n-\t(echo n; echo y) | git stash save --no-keep-index -p &&\n+\tset_state dir/foo work index &&\n+\t(echo y; echo n; echo y) | git stash save --no-keep-index -p &&\n+\tverify_state HEAD committed committed &&\n \tverify_state dir/foo head head &&\n \tverify_state bar bar_work dummy &&\n \tgit reset --hard &&\n \tgit stash apply --index &&\n-\tverify_state dir/foo work index &&\n-\tverify_state bar dummy bar_index\n+\tverify_state HEAD HEADfile_work HEADfile_index &&\n+\tverify_state bar dummy bar_index &&\n+\tverify_state dir/foo work index\n '\n \n test_expect_success PERL 'none of this moved HEAD' '\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex ef44fb2..a5e7e6b 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -17,6 +17,7 @@ test_expect_success 'stash save --include-untracked some dirty working directory\n \techo 3 > file &&\n \ttest_tick &&\n \techo 1 > file2 &&\n+\techo 1 > HEAD &&\n \tmkdir untracked &&\n \techo untracked >untracked/untracked &&\n \tgit stash --include-untracked &&\n@@ -35,6 +36,13 @@ test_expect_success 'stash save --include-untracked cleaned the untracked files'\n '\n \n cat > expect.diff <<EOF\n+diff --git a/HEAD b/HEAD\n+new file mode 100644\n+index 0000000..d00491f\n+--- /dev/null\n++++ b/HEAD\n+@@ -0,0 +1 @@\n++1\n diff --git a/file2 b/file2\n new file mode 100644\n index 0000000..d00491f\n@@ -51,14 +59,16 @@ index 0000000..5a72eb2\n +untracked\n EOF\n cat > expect.lstree <<EOF\n+HEAD\n file2\n untracked\n EOF\n \n test_expect_success 'stash save --include-untracked stashed the untracked files' '\n-\ttest \"!\" -f file2 &&\n-\ttest ! -e untracked &&\n-\tgit diff HEAD stash^3 -- file2 untracked >actual &&\n+\ttest_path_is_missing file2 &&\n+\ttest_path_is_missing untracked &&\n+\ttest_path_is_missing HEAD &&\n+\tgit diff HEAD stash^3 -- HEAD file2 untracked >actual &&\n \ttest_cmp expect.diff actual &&\n \tgit ls-tree --name-only stash^3: >actual &&\n \ttest_cmp expect.lstree actual\n@@ -75,6 +85,7 @@ git clean --force --quiet\n \n cat > expect <<EOF\n  M file\n+?? HEAD\n ?? actual\n ?? expect\n ?? file2\n@@ -116,10 +127,12 @@ test_expect_success 'stash save --include-untracked dirty index got stashed' '\n \n git reset > /dev/null\n \n+# Must direct output somewhere where it won't be considered an untracked file\n test_expect_success 'stash save --include-untracked -q is quiet' '\n \techo 1 > file5 &&\n-\tgit stash save --include-untracked --quiet > output.out 2>&1 &&\n-\ttest ! -s output.out\n+\tgit stash save --include-untracked --quiet > .git/stash-output.out 2>&1 &&\n+\ttest_line_count = 0 .git/stash-output.out &&\n+\trm -f .git/stash-output.out\n '\n \n test_expect_success 'stash save --include-untracked removed files' '\n@@ -133,7 +146,7 @@ rm -f expect\n \n test_expect_success 'stash save --include-untracked removed files got stashed' '\n \tgit stash pop &&\n-\ttest ! -f file\n+\ttest_path_is_missing file\n '\n \n cat > .gitignore <<EOF\n@@ -155,14 +168,14 @@ test_expect_success 'stash save --include-untracked respects .gitignore' '\n test_expect_success 'stash save -u can stash with only untracked files different' '\n \techo 4 > file4 &&\n \tgit stash -u &&\n-\ttest \"!\" -f file4\n+\ttest_path_is_missing file4\n '\n \n test_expect_success 'stash save --all does not respect .gitignore' '\n \tgit stash -a &&\n-\ttest \"!\" -f ignored &&\n-\ttest \"!\" -e ignored.d &&\n-\ttest \"!\" -f .gitignore\n+\ttest_path_is_missing ignored &&\n+\ttest_path_is_missing ignored.d &&\n+\ttest_path_is_missing .gitignore\n '\n \n test_expect_success 'stash save --all is stash poppable' '\n-- \n1.7.8\n\n\n\nJonathon Mah\nme@JonathonMah.com\n"},{"id":"181872","messageId":"7vhb0cvd3w.fsf@alter.siamese.dyndns.org","threadId":"29273","inReplyTo":"A244F415-73A1-4A77-BC4A-AC7F85946F02@JonathonMah.com","subject":"Re: [PATCHv2] stash: Don't fail if work dir contains file named 'HEAD'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-01-03T18:45:55Z","receivedAt":"2012-01-03T18:45:55Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, both.\n"}]}