{"thread":{"id":"24783","subject":"[PATCH v5 0/8] detached-stash: regularise handling of stash arguments by git stash","startedAt":"2010-08-18T13:09:32Z","lastAt":"2010-08-18T13:09:35Z","messageCount":4,"participants":["Jon Seymour"],"isPatch":true,"patchVersion":5,"patchTotal":8},"messages":[{"id":"148365","messageId":"1282136980-25793-1-git-send-email-jon.seymour@gmail.com","threadId":"24783","inReplyTo":null,"subject":"[PATCH v5 0/8] detached-stash: regularise handling of stash arguments by git stash","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-18T13:09:32Z","receivedAt":"2010-08-18T13:09:32Z","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 commanbds 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\nJon Seymour (8):\n  detached-stash: introduce parse_flags_and_revs function\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            |  140 +++++++++++++++++++++++++++\n 3 files changed, 296 insertions(+), 83 deletions(-)\n\n-- \n1.7.2.1.95.g969a4.dirty\n"},{"id":"148368","messageId":"1282136980-25793-2-git-send-email-jon.seymour@gmail.com","threadId":"24783","inReplyTo":"1282136980-25793-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v5 1/8] detached-stash: introduce parse_flags_and_revs function","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-18T13:09:33Z","receivedAt":"2010-08-18T13:09:33Z","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 at most one stash-like revision parameter and\nsero or more flags.\n\nIt knows how to parse -q,--quiet and --index flags, but leaves\nother flags unparsed.\n\nSpecified revisions are checked to see that they are at least stash-like\n(meaning: they look like something created by git stash save or git stash\ncreate).\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\na ensemble of derived variables, (w_commit, w_tree, b_commit, etc)\nare 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\nAn ensemble of supporting functions that make use of the state\nestablished by parse_flags_and_rev(). These are describe below.\nSubsequent patches in the series modify the existing\ngit stash subcommands to make use of these functions as appropriate.\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 |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 133 insertions(+), 0 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 1d95447..42b0da2 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -225,6 +225,138 @@ 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+\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+\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 +507,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.95.g4fabf\n"},{"id":"148367","messageId":"1282136980-25793-3-git-send-email-jon.seymour@gmail.com","threadId":"24783","inReplyTo":"1282136980-25793-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v5 2/8] detached-stash: simplify stash_apply","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-18T13:09:34Z","receivedAt":"2010-08-18T13:09:34Z","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.95.g4fabf\n"},{"id":"148366","messageId":"1282136980-25793-4-git-send-email-jon.seymour@gmail.com","threadId":"24783","inReplyTo":"1282136980-25793-1-git-send-email-jon.seymour@gmail.com","subject":"[PATCH v5 3/8] detached-stash: simplify stash_drop","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-08-18T13:09:35Z","receivedAt":"2010-08-18T13:09:35Z","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.95.g4fabf\n"}]}