{"thread":{"id":"24812","subject":"[PATCH v6 0/9] detached-stash: regularise handling of stash arguments by git stash","startedAt":"2010-08-21T04:08:55Z","lastAt":"2010-08-21T04:48:05Z","messageCount":12,"participants":["Jon Seymour"],"isPatch":true,"patchVersion":6,"patchTotal":9},"messages":[{"id":"148625","messageId":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":null,"subject":"[PATCH v6 0/9] detached-stash: regularise handling of stash arguments by git stash","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:08:55Z","receivedAt":"2010-08-21T04:08:55Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"This patch introduces a common flags and revision parsing function to the following git stash commands:\n * apply\n * branch\n * pop\n * drop\n * show\n\nWith these changes, git stash now:\n * allows non-stash log entry references to passed to 'stash branch' provided they are stash-like\n * relaxes the requirement that a stash log currently entry exists for 'stash show' or 'stash branch' \n * does not attempt to drop the specified revision if it doesn't look like a stash log entry reference\n * fails 'stash pop' and 'stash drop' early if the specified revision is not a stash log entry reference\n * fails early if more than one stash-like commit is specified\n * fails early if the specified revision is of the form ref@{n} and ref exists, but ref@{n} does not exist\n * reports various error conditions that can occur across multiple commands with consistent error messages.\n\nThe implementation of several commands is simplified to a lesser or greater degree by taking\nadvantage of the new common parsing and validation function, parse_flags_and_rev(). \n\nThis revision incorporates feedback and corrections from Johannes Sixt and Junio Hamano. \n\nVersion 5 differed from Version 4 by introducing a common parsing function and refactoring to\ntake advantage of that.\n\nVersion 6 differs from Version 5 by cleaning up and rationalising the new tests and splitting\nout a commit (2/9) that is only required to work around an issue with git rev-parse. \n\n2/9 of this series may be elided if this series is applied on top of the series:\n\n   \"rev-parse: improve reporting of invalid log references\"\n\nJon Seymour (9):\n  detached-stash: introduce parse_flags_and_revs function\n  detached-stash: work around git rev-parse failure to detect bad log refs\n  detached-stash: simplify stash_apply\n  detached-stash: simplify stash_drop\n  detached-stash: refactor git stash pop implementation\n  detached-stash: simplify git stash branch\n  detached-stash: simplify git stash show\n  detached-stash: tests of git stash with stash-like arguments\n  detached-stash: update Documentation\n\n Documentation/git-stash.txt |   16 ++-\n git-stash.sh                |  223 ++++++++++++++++++++++++++++---------------\n t/t3903-stash.sh            |  112 ++++++++++++++++++++++\n 3 files changed, 268 insertions(+), 83 deletions(-)\n\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148627","messageId":"1282363744-4924-2-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 1/9] detached-stash: introduce parse_flags_and_revs function","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:08:56Z","receivedAt":"2010-08-21T04:08:56Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Introduce parse_flags_and_revs. This function requires that\nthere is at most one stash-like revision parameter and\nzero or more flags.\n\nIt knows how to parse -q,--quiet and --index flags, but leaves\nother flags parsed.\n\nSpecified revisions are checked to see that they are at\nleast stash-like (meaning: they look like something created\nby git stash save or git stash create).\n\nIf this is so, then IS_STASH_LIKE is initialized to a non-empty value.\n\nIf the specified revision also looks like a stash log entry reference,\nthen IS_STASH_REF is initialized to a non-empty value.\n\nReferences of the form ref@{spec} are required to precisely identify\nan individual commit.\n\nIf no reference is specified, stash@{0} is assumed.\n\nOnce the specified reference is validated to be at least stash_like\nan ensemble of derived variables, (w_commit, w_tree, b_commit, etc)\nis initialized with a single call to git rev-parse.\n\nRepeated calls to parse_flags_and_rev() avoid repeated calls\nto git rev-parse if the specified arguments have already been\nparsed.\n\nSubsequent patches in the series modify the existing\ngit stash subcommands to make use of these functions\nas appropriate.\n\nAn ensemble of supporting functions that make use of the state\nestablished by parse_flags_and_rev(). These are described below:\n\nThe ancillary functions are:\n\nis_stash_like(): which can be used to test\nwhether a specified commit looks like a commit created with\ngit stash save or git stash create.\n\nassert_stash_like(): which can be used by\ncommands that misbehave unless their arguments stash-like.\n\nis_stash_ref(): which checks whether an argument\nis valid stash reference(e.g. is of the form\n['refs/']stash['@{'something'}])\n\nassert_stash_ref(): which can be used by commands\nthat misbehave unless their arguments are both stash-like and\nrefer to valid stash entries.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |  123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 123 insertions(+), 0 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 1d95447..b424a50 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -225,6 +225,128 @@ show_stash () {\n \tgit diff $flags $b_commit $w_commit\n }\n \n+#\n+# Parses the remaining options looking for flags and\n+# at most one revision defaulting to ${ref_stash}@{0}\n+# if none found.\n+#\n+# Derives related tree and commit objects from the\n+# revision, if one is found.\n+#\n+# stash records the work tree, and is a merge between the\n+# base commit (first parent) and the index tree (second parent).\n+#\n+#   REV is set to the symbolic version of the specified stash-like commit\n+#   IS_STASH_LIKE is non-blank if ${REV} looks like a stash\n+#   IS_STASH_REF is non-blank if the ${REV} looks like a stash ref\n+#   s is set to the SHA1 of the stash commit\n+#   w_commit is set to the commit containing the working tree\n+#   b_commit is set to the base commit\n+#   i_commit is set to the commit containing the index tree\n+#   w_tree is set to the working tree\n+#   b_tree is set to the base tree\n+#   i_tree is set to the index tree\n+#\n+#   GIT_QUIET is set to t if -q is specified\n+#   INDEX_OPTION is set to --index if --index is specified.\n+#   FLAGS is set to the remaining flags\n+#\n+# dies if:\n+#   * too many revisions specified\n+#   * no revision is specified and there is no stash stack\n+#   * a revision is specified which cannot be resolve to a SHA1\n+#   * a non-existent stash reference is specified\n+#\n+\n+parse_flags_and_rev()\n+{\n+\ttest \"$PARSE_CACHE\" = \"$*\" && return 0 # optimisation\n+\tPARSE_CACHE=\"$*\"\n+\n+\tIS_STASH_LIKE=\n+\tIS_STASH_REF=\n+\tINDEX_OPTION=\n+\ts=\n+\tw_commit=\n+\tb_commit=\n+\ti_commit=\n+\tw_tree=\n+\tb_tree=\n+\ti_tree=\n+\n+\tREV=$(git rev-parse --no-flags --symbolic \"$@\" 2>/dev/null)\n+\tFLAGS=$(git rev-parse --no-revs -- \"$@\" 2>/dev/null)\n+\n+\tset -- $FLAGS\n+\n+\tFLAGS=\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t\t-q|--quiet)\n+\t\t\t\tGIT_QUIET=-t\n+\t\t\t;;\n+\t\t\t--index)\n+\t\t\t\tINDEX_OPTION=--index\n+\t\t\t;;\n+\t\t\t--)\n+\t\t\t\t:\n+\t\t\t;;\n+\t\t\t*)\n+\t\t\t\tFLAGS=\"${FLAGS}${FLAGS:+ }$1\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tset -- $REV\n+\n+\tcase $# in\n+\t\t0)\n+\t\t\thave_stash || die \"No stash found.\"\n+\t\t\tset -- ${ref_stash}@{0}\n+\t\t;;\n+\t\t1)\n+\t\t\t:\n+\t\t;;\n+\t\t*)\n+\t\t\tdie \"Too many revisions specified: $REV\"\n+\t\t;;\n+\tesac\n+\n+\tREV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || die \"$1 is not valid reference\"\n+\n+\ti_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) &&\n+\tset -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) &&\n+\ts=$1 &&\n+\tw_commit=$1 &&\n+\tb_commit=$2 &&\n+\tw_tree=$3 &&\n+\tb_tree=$4 &&\n+\ti_tree=$5 &&\n+\tIS_STASH_LIKE=t &&\n+\ttest \"$ref_stash\" = \"$(git rev-parse --symbolic-full-name \"${REV%@*}\")\" &&\n+\tIS_STASH_REF=t\n+\n+\n+is_stash_like()\n+{\n+\tparse_flags_and_rev \"$@\"\n+\ttest -n \"$IS_STASH_LIKE\"\n+}\n+\n+assert_stash_like() {\n+\tis_stash_like \"$@\" || die \"'$*' is not a stash-like commit\"\n+}\n+\n+is_stash_ref() {\n+\tis_stash_like \"$@\" && test -n \"$IS_STASH_REF\"\n+}\n+\n+assert_stash_ref() {\n+\tis_stash_ref \"$@\" || die \"'$*' is not a stash reference\"\n+}\n+\n apply_stash () {\n \tapplied_stash=\n \tunstash_index=\n@@ -375,6 +497,7 @@ apply_to_branch () {\n \tdrop_stash $stash\n }\n \n+PARSE_CACHE='--not-parsed'\n # The default command is \"save\" if nothing but options are given\n seen_non_option=\n for opt\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148628","messageId":"1282363744-4924-3-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 2/9] detached-stash: work around git rev-parse failure to detect bad log refs","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:08:57Z","receivedAt":"2010-08-21T04:08:57Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"This commit is required because git rev-parse in 1.7.2 does not correctly\nindicate invalid log references using a non-zero status code.\n\nWe use a proxy for the condition (non-empty error output) as\na substitute. This commit can be reverted when, and if, rev-parse\nis fixed to indicate invalid log references with a status code.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   10 ++++++++++\n 1 files changed, 10 insertions(+), 0 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex b424a50..42b0da2 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -328,6 +328,16 @@ parse_flags_and_rev()\n \ttest \"$ref_stash\" = \"$(git rev-parse --symbolic-full-name \"${REV%@*}\")\" &&\n \tIS_STASH_REF=t\n \n+\tif test \"${REV}\" != \"${REV%{*\\}}\"\n+\tthen\n+\t\t# maintainers: it would be better if git rev-parse indicated\n+\t\t# this condition with a non-zero status code but as of 1.7.2.1 it\n+\t\t# it did not. So, we use non-empty stderr output as a proxy for the\n+\t\t# condition of interest.\n+\t\ttest -z \"$(git rev-parse \"$REV\" 2>&1 >/dev/null)\" || die \"$REV does not exist in the stash log\"\n+\tfi\n+\n+}\n \n is_stash_like()\n {\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148626","messageId":"1282363744-4924-4-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 3/9] detached-stash: simplify stash_apply","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:08:58Z","receivedAt":"2010-08-21T04:08:58Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"The implementation of stash_apply() is simplified to take\nadvantage of the common parsing function parse_flags_and_rev().\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   38 +++-----------------------------------\n 1 files changed, 3 insertions(+), 35 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 42b0da2..ba68f1e 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -358,40 +358,8 @@ assert_stash_ref() {\n }\n \n apply_stash () {\n-\tapplied_stash=\n-\tunstash_index=\n \n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t--index)\n-\t\t\tunstash_index=t\n-\t\t\t;;\n-\t\t-q|--quiet)\n-\t\t\tGIT_QUIET=t\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-\tif test $# = 0\n-\tthen\n-\t\thave_stash || die 'Nothing to apply'\n-\t\tapplied_stash=\"$ref_stash@{0}\"\n-\telse\n-\t\tapplied_stash=\"$*\"\n-\tfi\n-\n-\t# stash records the work tree, and is a merge between the\n-\t# base commit (first parent) and the index tree (second parent).\n-\ts=$(git rev-parse --quiet --verify --default $ref_stash \"$@\") &&\n-\tw_tree=$(git rev-parse --quiet --verify \"$s:\") &&\n-\tb_tree=$(git rev-parse --quiet --verify \"$s^1:\") &&\n-\ti_tree=$(git rev-parse --quiet --verify \"$s^2:\") ||\n-\t\tdie \"$*: no valid stashed state found\"\n+\tassert_stash_like \"$@\"\n \n \tgit update-index -q --refresh &&\n \tgit diff-files --quiet --ignore-submodules ||\n@@ -402,7 +370,7 @@ apply_stash () {\n \t\tdie 'Cannot apply a stash in the middle of a merge'\n \n \tunstashed_index_tree=\n-\tif test -n \"$unstash_index\" && test \"$b_tree\" != \"$i_tree\" &&\n+\tif test -n \"$INDEX_OPTION\" && test \"$b_tree\" != \"$i_tree\" &&\n \t\t\ttest \"$c_tree\" != \"$i_tree\"\n \tthen\n \t\tgit diff-tree --binary $s^2^..$s^2 | git apply --cached\n@@ -447,7 +415,7 @@ apply_stash () {\n \telse\n \t\t# Merge conflict; keep the exit status from merge-recursive\n \t\tstatus=$?\n-\t\tif test -n \"$unstash_index\"\n+\t\tif test -n \"$INDEX_OPTION\"\n \t\tthen\n \t\t\techo >&2 'Index was not unstashed.'\n \t\tfi\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148629","messageId":"1282363744-4924-5-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 4/9] detached-stash: simplify stash_drop","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:08:59Z","receivedAt":"2010-08-21T04:08:59Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Previously, git stash drop would fail noisily while executing git reflog\ndelete if the specified revision was not a stash reference.\n\nNow, git stash drop fails with an error message which more precisely\nindicates the reason for failure.\n\nFurthermore, git stash drop will now fail with a non-zero status code\nif stash@{n} specifies a stash log entry that does not actually exist.\n\nThis change in behaviour is achieved by delegating argument parsing\nto the common parse_flags_and_rev() function (via a call to\nassert_stash_ref).\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   31 +++----------------------------\n 1 files changed, 3 insertions(+), 28 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ba68f1e..750f360 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -424,35 +424,10 @@ apply_stash () {\n }\n \n drop_stash () {\n-\thave_stash || die 'No stash entries to drop'\n+\tassert_stash_ref \"$@\"\n \n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t-q|--quiet)\n-\t\t\tGIT_QUIET=t\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-\tif test $# = 0\n-\tthen\n-\t\tset x \"$ref_stash@{0}\"\n-\t\tshift\n-\tfi\n-\t# Verify supplied argument looks like a stash entry\n-\ts=$(git rev-parse --verify \"$@\") &&\n-\tgit rev-parse --verify \"$s:\"   > /dev/null 2>&1 &&\n-\tgit rev-parse --verify \"$s^1:\" > /dev/null 2>&1 &&\n-\tgit rev-parse --verify \"$s^2:\" > /dev/null 2>&1 ||\n-\t\tdie \"$*: not a valid stashed state\"\n-\n-\tgit reflog delete --updateref --rewrite \"$@\" &&\n-\t\tsay \"Dropped $* ($s)\" || die \"$*: Could not drop stash entry\"\n+\tgit reflog delete --updateref --rewrite \"${REV}\" &&\n+\t\tsay \"Dropped ${REV} ($s)\" || die \"${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-- \n1.7.2.1.110.g34f32\n"},{"id":"148633","messageId":"1282363744-4924-6-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 5/9] detached-stash: refactor git stash pop implementation","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:09:00Z","receivedAt":"2010-08-21T04:09:00Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"git stash pop is abstracted into its own implementation function - pop_stash.\n\nThe behaviour is changed so that git stash pop fails early if the\nthe specified stash reference does not exist or does not refer to\nan extant entry in the reflog of the reference stash.\n\nThis fixes the case where the apply succeeds, but the drop fails.\nPreviously this caused caused git stash pop to exit with a non-zero exit code\nand a dirty tree.\n\nNow, git stash pop fails with a non-zero exit code, but the working\ntree is not modified.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   12 ++++++++----\n 1 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 750f360..ac4c0f6 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -423,6 +423,13 @@ apply_stash () {\n \tfi\n }\n \n+pop_stash() {\n+\tassert_stash_ref \"$@\"\n+\n+\tapply_stash \"$@\" &&\n+\tdrop_stash \"$@\"\n+}\n+\n drop_stash () {\n \tassert_stash_ref \"$@\"\n \n@@ -498,10 +505,7 @@ drop)\n \t;;\n pop)\n \tshift\n-\tif apply_stash \"$@\"\n-\tthen\n-\t\tdrop_stash \"$applied_stash\"\n-\tfi\n+\tpop_stash \"$@\"\n \t;;\n branch)\n \tshift\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148634","messageId":"1282363744-4924-7-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 6/9] detached-stash: simplify git stash branch","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:09:01Z","receivedAt":"2010-08-21T04:09:01Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"This patch teaches git stash branch to tolerate stash-like arguments.\n\nIn particular, a stash is only required if an argument isn't specified\nand the stash is only dropped if a stash entry reference was\nspecified or implied.\n\nThe implementation has been simplified by taking advantage of\nassert_stash_like() and the variables established by\nparse_flags_and_rev().\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   17 +++++++----------\n 1 files changed, 7 insertions(+), 10 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ac4c0f6..ff1edc9 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -441,20 +441,17 @@ drop_stash () {\n }\n \n apply_to_branch () {\n-\thave_stash || die 'Nothing to apply'\n-\n \ttest -n \"$1\" || die 'No branch name specified'\n \tbranch=$1\n+\tshift 1\n \n-\tif test -z \"$2\"\n-\tthen\n-\t\tset x \"$ref_stash@{0}\"\n-\tfi\n-\tstash=$2\n+\tset -- --index \"$@\"\n+\tassert_stash_like \"$@\"\n+\n+\tgit checkout -b $branch $REV^ &&\n+\tapply_stash \"$@\"\n \n-\tgit checkout -b $branch $stash^ &&\n-\tapply_stash --index $stash &&\n-\tdrop_stash $stash\n+\ttest -z \"$IS_STASH_REF\" || drop_stash \"$@\"\n }\n \n PARSE_CACHE='--not-parsed'\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148631","messageId":"1282363744-4924-8-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 7/9] detached-stash: simplify git stash show","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:09:02Z","receivedAt":"2010-08-21T04:09:02Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"This commit refactors git stash show to make use of the assert_stash_like function.\n\ngit show now dies if the presented argument is non-stash-like.\n\nPrevious behaviour was to tolerate commits that were not even stash-like.\n\nPreviously, git stash show would accept stash-like arguments, but\nonly if there was a stash on the stack.\n\nNow, git stash accepts stash-like arguments always and only fails\nif no stash-like argument is specified and there is no stash stack.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |   14 ++------------\n 1 files changed, 2 insertions(+), 12 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex ff1edc9..7ce818b 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -210,19 +210,9 @@ list_stash () {\n }\n \n show_stash () {\n-\thave_stash || die 'No stash found'\n-\n-\tflags=$(git rev-parse --no-revs --flags \"$@\")\n-\tif test -z \"$flags\"\n-\tthen\n-\t\tflags=--stat\n-\tfi\n-\n-\tw_commit=$(git rev-parse --quiet --verify --default $ref_stash \"$@\") &&\n-\tb_commit=$(git rev-parse --quiet --verify \"$w_commit^\") ||\n-\t\tdie \"'$*' is not a stash\"\n+\tassert_stash_like \"$@\"\n \n-\tgit diff $flags $b_commit $w_commit\n+\tgit diff ${FLAGS:---stat} $b_commit $w_commit\n }\n \n #\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148632","messageId":"1282363744-4924-9-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 8/9] detached-stash: tests of git stash with stash-like arguments","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:09:03Z","receivedAt":"2010-08-21T04:09:03Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Adds new tests which check that:\n* git stash branch handles a stash-like argument when there is a stash stack\n* git stash branch handles a stash-like argument when there is not a stash stack\n* git stash show handles a stash-like argument when there is a stash stack\n* git stash show handles a stash-like argument when there is not a stash stack\n* git stash drop fails early if the specified argument is not a stash reference\n* git stash pop fails early if the specified argument is not a stash reference\n* git stash * fails early if the reference supplied is bogus\n* git stash fails early with stash@{n} where n >= length of stash log\n\n| Amended per advice from Johannes Sixt to avoid burying stash create failures.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n t/t3903-stash.sh |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 112 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 62e208a..ea9f979 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -378,4 +378,116 @@ test_expect_failure 'stash file to directory' '\n \ttest foo = \"$(cat file/file)\"\n '\n \n+test_expect_success 'stash branch - no stashes on stack, stash-like argument' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD\" &&\n+\tgit reset --hard &&\n+\techo foo >> file &&\n+\tSTASH_ID=$(git stash create) &&\n+\tgit reset --hard &&\n+\tgit stash branch stash-branch ${STASH_ID} &&\n+\ttest_when_finished \"git reset --hard HEAD && git checkout master && git branch -D stash-branch\" &&\n+\ttest $(git ls-files --modified | wc -l) -eq 1\n+'\n+\n+test_expect_success 'stash branch - stashes on stack, stash-like argument' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD\" &&\n+\tgit reset --hard &&\n+\techo foo >> file &&\n+\tgit stash &&\n+\ttest_when_finished \"git stash drop\" &&\n+\techo bar >> file &&\n+\tSTASH_ID=$(git stash create) &&\n+\tgit reset --hard &&\n+\tgit stash branch stash-branch ${STASH_ID} &&\n+\ttest_when_finished \"git reset --hard HEAD && git checkout master && git branch -D stash-branch\" &&\n+\ttest $(git ls-files --modified | wc -l) -eq 1\n+'\n+\n+test_expect_success 'stash show - stashes on stack, stash-like argument' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD\" &&\n+\tgit reset --hard &&\n+\techo foo >> file &&\n+\tgit stash &&\n+\ttest_when_finished \"git stash drop\" &&\n+\techo bar >> file &&\n+\tSTASH_ID=$(git stash create) &&\n+\tgit reset --hard &&\n+\tgit stash show ${STASH_ID}\n+'\n+test_expect_success 'stash show - no stashes on stack, stash-like argument' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD\" &&\n+\tgit reset --hard &&\n+\techo foo >> file &&\n+\tSTASH_ID=$(git stash create) &&\n+\tgit reset --hard &&\n+\tgit stash show ${STASH_ID}\n+'\n+\n+test_expect_success 'stash drop - fail early if specified stash is not a stash reference' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD && git stash clear\" &&\n+\tgit reset --hard &&\n+\techo foo > file &&\n+\tgit stash &&\n+\techo bar > file &&\n+\tgit stash &&\n+\ttest_must_fail \"git stash drop $(git rev-parse stash@{0})\" &&\n+\tgit stash pop &&\n+\ttest bar = \"$(cat file)\" &&\n+\tgit reset --hard HEAD\n+'\n+\n+test_expect_success 'stash pop - fail early if specified stash is not a stash reference' '\n+\tgit stash clear &&\n+\ttest_when_finished \"git reset --hard HEAD && git stash clear\" &&\n+\tgit reset --hard &&\n+\techo foo > file &&\n+\tgit stash &&\n+\techo bar > file &&\n+\tgit stash &&\n+\ttest_must_fail \"git stash pop $(git rev-parse stash@{0})\" &&\n+\tgit stash pop &&\n+\ttest bar = \"$(cat file)\" &&\n+\tgit reset --hard HEAD\n+'\n+\n+test_expect_success 'ref with non-existant reflog' '\n+\tgit stash clear &&\n+\techo bar5 > file &&\n+\techo bar6 > file2 &&\n+\tgit add file2 &&\n+\tgit stash &&\n+\t! \"git rev-parse --quiet --verify does-not-exist\" &&\n+\ttest_must_fail \"git stash drop does-not-exist\" &&\n+\ttest_must_fail \"git stash drop does-not-exist@{0}\" &&\n+\ttest_must_fail \"git stash pop does-not-exist\" &&\n+\ttest_must_fail \"git stash pop does-not-exist@{0}\" &&\n+\ttest_must_fail \"git stash apply does-not-exist\" &&\n+\ttest_must_fail \"git stash apply does-not-exist@{0}\" &&\n+\ttest_must_fail \"git stash show does-not-exist\" &&\n+\ttest_must_fail \"git stash show does-not-exist@{0}\" &&\n+\ttest_must_fail \"git stash branch tmp does-not-exist\" &&\n+\ttest_must_fail \"git stash branch tmp does-not-exist@{0}\" &&\n+\tgit stash drop\n+'\n+\n+test_expect_success 'invalid ref of the form stash@{n}, n >= N' '\n+\tgit stash clear &&\n+\ttest_must_fail \"git stash drop stash@{0}\" &&\n+\techo bar5 > file &&\n+\techo bar6 > file2 &&\n+\tgit add file2 &&\n+\tgit stash &&\n+\ttest_must_fail \"git drop stash@{1}\" &&\n+\ttest_must_fail \"git pop stash@{1}\" &&\n+\ttest_must_fail \"git apply stash@{1}\" &&\n+\ttest_must_fail \"git show stash@{1}\" &&\n+\ttest_must_fail \"git branch tmp stash@{1}\" &&\n+\tgit stash drop\n+'\n+\n test_done\n-- \n1.7.2.1.110.g34f32\n"},{"id":"148630","messageId":"1282363744-4924-10-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6 9/9] detached-stash: update Documentation","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:09:04Z","receivedAt":"2010-08-21T04:09:04Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"Update the documentation to indicate that git stash branch only attempts\nto drop the specified stash if it looks like stash reference.\n\nAlso changed the synopsis to more clearly indicate which commands require\na stash entry reference as opposed to merely a stash-like commit.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n Documentation/git-stash.txt |   16 +++++++++++-----\n 1 files changed, 11 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt\nindex 473889a..8728f7a 100644\n--- a/Documentation/git-stash.txt\n+++ b/Documentation/git-stash.txt\n@@ -104,18 +104,22 @@ tree's changes, but also the index's ones. However, this can fail, when you\n have conflicts (which are stored in the index, where you therefore can no\n longer apply the changes as they were originally).\n +\n-When no `<stash>` is given, `stash@\\{0}` is assumed.\n+When no `<stash>` is given, `stash@\\{0}` is assumed, otherwise `<stash>` must\n+be a reference of the form `stash@\\{<revision>}`.\n \n apply [--index] [-q|--quiet] [<stash>]::\n \n-\tLike `pop`, but do not remove the state from the stash list.\n+\tLike `pop`, but do not remove the state from the stash list. Unlike `pop`,\n+\t`<stash>` may be any commit that looks like a commit created by\n+\t`stash save` or `stash create`.\n \n branch <branchname> [<stash>]::\n \n \tCreates and checks out a new branch named `<branchname>` starting from\n \tthe commit at which the `<stash>` was originally created, applies the\n-\tchanges recorded in `<stash>` to the new working tree and index, then\n-\tdrops the `<stash>` if that completes successfully. When no `<stash>`\n+\tchanges recorded in `<stash>` to the new working tree and index.\n+\tIf that succeeds, and `<stash>` is a reference of the form\n+\t`stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>`\n \tis given, applies the latest one.\n +\n This is useful if the branch on which you ran `git stash save` has\n@@ -132,7 +136,9 @@ clear::\n drop [-q|--quiet] [<stash>]::\n \n \tRemove a single stashed state from the stash list. When no `<stash>`\n-\tis given, it removes the latest one. i.e. `stash@\\{0}`\n+\tis given, it removes the latest one. i.e. `stash@\\{0}`, otherwise\n+\t`<stash>` must a valid stash log reference of the form\n+\t`stash@\\{<revision>}`.\n \n create::\n \n-- \n1.7.2.1.110.g34f32\n"},{"id":"148635","messageId":"1282365982-11091-1-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-2-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6a 1/9] detached-stash: introduce parse_flags_and_revs function","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:46:22Z","receivedAt":"2010-08-21T04:46:22Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"| amended to ensure trailing } is in 1/9\n\nIntroduce parse_flags_and_revs. This function requires that\nthere is at most one stash-like revision parameter and\nzero or more flags.\n\nIt knows how to parse -q,--quiet and --index flags, but leaves\nother flags parsed.\n\nSpecified revisions are checked to see that they are at\nleast stash-like (meaning: they look like something created\nby git stash save or git stash create).\n\nIf this is so, then IS_STASH_LIKE is initialized to a non-empty value.\n\nIf the specified revision also looks like a stash log entry reference,\nthen IS_STASH_REF is initialized to a non-empty value.\n\nReferences of the form ref@{spec} are required to precisely identify\nan individual commit.\n\nIf no reference is specified, stash@{0} is assumed.\n\nOnce the specified reference is validated to be at least stash_like\nan ensemble of derived variables, (w_commit, w_tree, b_commit, etc)\nis initialized with a single call to git rev-parse.\n\nRepeated calls to parse_flags_and_rev() avoid repeated calls\nto git rev-parse if the specified arguments have already been\nparsed.\n\nSubsequent patches in the series modify the existing\ngit stash subcommands to make use of these functions\nas appropriate.\n\nAn ensemble of supporting functions that make use of the state\nestablished by parse_flags_and_rev(). These are described below:\n\nThe ancillary functions are:\n\nis_stash_like(): which can be used to test\nwhether a specified commit looks like a commit created with\ngit stash save or git stash create.\n\nassert_stash_like(): which can be used by\ncommands that misbehave unless their arguments stash-like.\n\nis_stash_ref(): which checks whether an argument\nis valid stash reference(e.g. is of the form\n['refs/']stash['@{'something'}])\n\nassert_stash_ref(): which can be used by commands\nthat misbehave unless their arguments are both stash-like and\nrefer to valid stash entries.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |  124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 124 insertions(+), 0 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 1d95447..836d6e6 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -225,6 +225,129 @@ show_stash () {\n \tgit diff $flags $b_commit $w_commit\n }\n \n+#\n+# Parses the remaining options looking for flags and\n+# at most one revision defaulting to ${ref_stash}@{0}\n+# if none found.\n+#\n+# Derives related tree and commit objects from the\n+# revision, if one is found.\n+#\n+# stash records the work tree, and is a merge between the\n+# base commit (first parent) and the index tree (second parent).\n+#\n+#   REV is set to the symbolic version of the specified stash-like commit\n+#   IS_STASH_LIKE is non-blank if ${REV} looks like a stash\n+#   IS_STASH_REF is non-blank if the ${REV} looks like a stash ref\n+#   s is set to the SHA1 of the stash commit\n+#   w_commit is set to the commit containing the working tree\n+#   b_commit is set to the base commit\n+#   i_commit is set to the commit containing the index tree\n+#   w_tree is set to the working tree\n+#   b_tree is set to the base tree\n+#   i_tree is set to the index tree\n+#\n+#   GIT_QUIET is set to t if -q is specified\n+#   INDEX_OPTION is set to --index if --index is specified.\n+#   FLAGS is set to the remaining flags\n+#\n+# dies if:\n+#   * too many revisions specified\n+#   * no revision is specified and there is no stash stack\n+#   * a revision is specified which cannot be resolve to a SHA1\n+#   * a non-existent stash reference is specified\n+#\n+\n+parse_flags_and_rev()\n+{\n+\ttest \"$PARSE_CACHE\" = \"$*\" && return 0 # optimisation\n+\tPARSE_CACHE=\"$*\"\n+\n+\tIS_STASH_LIKE=\n+\tIS_STASH_REF=\n+\tINDEX_OPTION=\n+\ts=\n+\tw_commit=\n+\tb_commit=\n+\ti_commit=\n+\tw_tree=\n+\tb_tree=\n+\ti_tree=\n+\n+\tREV=$(git rev-parse --no-flags --symbolic \"$@\" 2>/dev/null)\n+\tFLAGS=$(git rev-parse --no-revs -- \"$@\" 2>/dev/null)\n+\n+\tset -- $FLAGS\n+\n+\tFLAGS=\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t\t-q|--quiet)\n+\t\t\t\tGIT_QUIET=-t\n+\t\t\t;;\n+\t\t\t--index)\n+\t\t\t\tINDEX_OPTION=--index\n+\t\t\t;;\n+\t\t\t--)\n+\t\t\t\t:\n+\t\t\t;;\n+\t\t\t*)\n+\t\t\t\tFLAGS=\"${FLAGS}${FLAGS:+ }$1\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tset -- $REV\n+\n+\tcase $# in\n+\t\t0)\n+\t\t\thave_stash || die \"No stash found.\"\n+\t\t\tset -- ${ref_stash}@{0}\n+\t\t;;\n+\t\t1)\n+\t\t\t:\n+\t\t;;\n+\t\t*)\n+\t\t\tdie \"Too many revisions specified: $REV\"\n+\t\t;;\n+\tesac\n+\n+\tREV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || die \"$1 is not valid reference\"\n+\n+\ti_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) &&\n+\tset -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) &&\n+\ts=$1 &&\n+\tw_commit=$1 &&\n+\tb_commit=$2 &&\n+\tw_tree=$3 &&\n+\tb_tree=$4 &&\n+\ti_tree=$5 &&\n+\tIS_STASH_LIKE=t &&\n+\ttest \"$ref_stash\" = \"$(git rev-parse --symbolic-full-name \"${REV%@*}\")\" &&\n+\tIS_STASH_REF=t\n+\n+}\n+\n+is_stash_like()\n+{\n+\tparse_flags_and_rev \"$@\"\n+\ttest -n \"$IS_STASH_LIKE\"\n+}\n+\n+assert_stash_like() {\n+\tis_stash_like \"$@\" || die \"'$*' is not a stash-like commit\"\n+}\n+\n+is_stash_ref() {\n+\tis_stash_like \"$@\" && test -n \"$IS_STASH_REF\"\n+}\n+\n+assert_stash_ref() {\n+\tis_stash_ref \"$@\" || die \"'$*' is not a stash reference\"\n+}\n+\n apply_stash () {\n \tapplied_stash=\n \tunstash_index=\n@@ -375,6 +498,7 @@ apply_to_branch () {\n \tdrop_stash $stash\n }\n \n+PARSE_CACHE='--not-parsed'\n # The default command is \"save\" if nothing but options are given\n seen_non_option=\n for opt\n-- \n1.7.2.2.178.g949b\n"},{"id":"148636","messageId":"1282366085-11196-1-git-send-email-jon.seymour@gmail.com","threadId":"24812","inReplyTo":"1282363744-4924-3-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v6a 2/9] detached-stash: work around git rev-parse failure to detect bad log refs","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-21T04:48:05Z","receivedAt":"2010-08-21T04:48:05Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"| amended to include trailing } in 1/9\n\nThis commit is required because git rev-parse in 1.7.2 does not correctly\nindicate invalid log references using a non-zero status code.\n\nWe use a proxy for the condition (non-empty error output) as\na substitute. This commit can be reverted when, and if, rev-parse\nis fixed to indicate invalid log references with a status code.\n\nSigned-off-by: Jon Seymour <jon.seymour@gmail.com>\n---\n git-stash.sh |    9 +++++++++\n 1 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 836d6e6..42b0da2 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -328,6 +328,15 @@ parse_flags_and_rev()\n \ttest \"$ref_stash\" = \"$(git rev-parse --symbolic-full-name \"${REV%@*}\")\" &&\n \tIS_STASH_REF=t\n \n+\tif test \"${REV}\" != \"${REV%{*\\}}\"\n+\tthen\n+\t\t# maintainers: it would be better if git rev-parse indicated\n+\t\t# this condition with a non-zero status code but as of 1.7.2.1 it\n+\t\t# it did not. So, we use non-empty stderr output as a proxy for the\n+\t\t# condition of interest.\n+\t\ttest -z \"$(git rev-parse \"$REV\" 2>&1 >/dev/null)\" || die \"$REV does not exist in the stash log\"\n+\tfi\n+\n }\n \n is_stash_like()\n-- \n1.7.2.2.178.g949b\n"}]}