stash: allow stashes to be referenced by index only
authorAaron M Watson <watsona4@gmail.com>
Mon, 24 Oct 2016 23:40:13 +0000 (19:40 -0400)
committerJunio C Hamano <gitster@pobox.com>
Wed, 26 Oct 2016 16:58:10 +0000 (09:58 -0700)
Instead of referencing "stash@{n}" explicitly, make it possible to
simply reference as "n". Most users only reference stashes by their
position in the stash stack (what I refer to as the "index" here).

The syntax for the typical stash (stash@{n}) is slightly annoying and
easy to forget, and sometimes difficult to escape properly in a
script. Because of this the capability to do things with the stash by
simply referencing the index is desirable.

This patch includes the superior implementation provided by Ă˜sse Walle
(thanks for that), with a slight change to fix a broken test in the test
suite. I also merged the test scripts as suggested by Jeff King, and
un-wrapped the documentation as suggested by Junio Hamano.

Signed-off-by: Aaron M Watson <watsona4@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Documentation/git-stash.txt
git-stash.sh
t/t3903-stash.sh
index 92df596e5fe9757fee399078e05e3ba44196fda3..2e9cef06e64376e973eeb74e338d93dd99ae40ee 100644 (file)
@@ -39,7 +39,8 @@ The latest stash you created is stored in `refs/stash`; older
 stashes are found in the reflog of this reference and can be named using
 the usual reflog syntax (e.g. `stash@{0}` is the most recently
 created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
-is also possible).
+is also possible). Stashes may also be referenced by specifying just the
+stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
 
 OPTIONS
 -------
index 90d63f293e8359f63a3c2350850fcad17de2b455..4546abaaef3dab9e0c4dc719f111682f1cb1dd57 100755 (executable)
@@ -384,9 +384,8 @@ parse_flags_and_rev()
        i_tree=
        u_tree=
 
-       REV=$(git rev-parse --no-flags --symbolic --sq "$@") || exit 1
-
        FLAGS=
+       REV=
        for opt
        do
                case "$opt" in
@@ -404,6 +403,9 @@ parse_flags_and_rev()
                                        die "$(eval_gettext "unknown option: \$opt")"
                                FLAGS="${FLAGS}${FLAGS:+ }$opt"
                        ;;
+                       *)
+                               REV="${REV}${REV:+ }'$opt'"
+                       ;;
                esac
        done
 
@@ -422,6 +424,15 @@ parse_flags_and_rev()
                ;;
        esac
 
+       case "$1" in
+               *[!0-9]*)
+                       :
+               ;;
+               *)
+                       set -- "${ref_stash}@{$1}"
+               ;;
+       esac
+
        REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
                reference="$1"
                die "$(eval_gettext "\$reference is not a valid reference")"
index 2142c1fa92017bc47cfc4ccb1f25e16fc0eec1a4..e1a6ccc00c5988cfa8808bccc49a5e21703166b6 100755 (executable)
@@ -131,6 +131,26 @@ test_expect_success 'drop middle stash' '
        test 1 = $(git show HEAD:file)
 '
 
+test_expect_success 'drop middle stash by index' '
+       git reset --hard &&
+       echo 8 >file &&
+       git stash &&
+       echo 9 >file &&
+       git stash &&
+       git stash drop 1 &&
+       test 2 = $(git stash list | wc -l) &&
+       git stash apply &&
+       test 9 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file) &&
+       git reset --hard &&
+       git stash drop &&
+       git stash apply &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
 test_expect_success 'stash pop' '
        git reset --hard &&
        git stash pop &&
@@ -604,6 +624,21 @@ test_expect_success 'invalid ref of the form stash@{n}, n >= N' '
        git stash drop
 '
 
+test_expect_success 'invalid ref of the form "n", n >= N' '
+       git stash clear &&
+       test_must_fail git stash drop 0 &&
+       echo bar5 >file &&
+       echo bar6 >file2 &&
+       git add file2 &&
+       git stash &&
+       test_must_fail git stash drop 1 &&
+       test_must_fail git stash pop 1 &&
+       test_must_fail git stash apply 1 &&
+       test_must_fail git stash show 1 &&
+       test_must_fail git stash branch tmp 1 &&
+       git stash drop
+'
+
 test_expect_success 'stash branch should not drop the stash if the branch exists' '
        git stash clear &&
        echo foo >file &&