Teach git-stash to "apply --index"
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Mon, 2 Jul 2007 11:14:49 +0000 (12:14 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 6 Jul 2007 08:43:24 +0000 (01:43 -0700)
When given this subcommand, git-stash will try to merge the stashed
index into the current one. Only trivial merges are possible, since
we have no index for the index ;-) If a trivial merge is not possible,
git-stash will bail out with a hint to skip the --index option.

For good measure, finally include a test case.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-stash.sh
t/t3903-stash.sh [new file with mode: 0755]

index f01494d..5c63ca5 100755 (executable)
@@ -111,6 +111,13 @@ apply_stash () {
        git diff-files --quiet ||
                die 'Cannot restore on top of a dirty state'
 
+       unstash_index=
+       case "$1" in
+       --index)
+               unstash_index=t
+               shift
+       esac
+
        # current index state
        c_tree=$(git write-tree) ||
                die 'Cannot apply a stash in the middle of a merge'
@@ -120,6 +127,15 @@ apply_stash () {
        b_tree=$(git rev-parse --verify "$s^:") ||
                die "$*: no valid stashed state found"
 
+       test -z "$unstash_index" || {
+               git diff --binary $s^2^..$s^2 | git apply --cached
+               test $? -ne 0 &&
+                       die 'Conflicts in index. Try without --index.'
+               unstashed_index_tree=$(git-write-tree) ||
+                       die 'Could not save index tree'
+               git reset
+       }
+
        eval "
                GITHEAD_$w_tree='Stashed changes' &&
                GITHEAD_$c_tree='Updated upstream' &&
@@ -137,9 +153,12 @@ apply_stash () {
                        die "Cannot unstage modified files"
                git-status
                rm -f "$a"
+               test -z "$unstash_index" || git read-tree $unstashed_index_tree
        else
                # Merge conflict; keep the exit status from merge-recursive
-               exit
+               status=$?
+               test -z "$unstash_index" || echo 'Index was not unstashed.' >&2
+               exit $status
        fi
 }
 
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
new file mode 100755 (executable)
index 0000000..392ac1c
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E Schindelin
+#
+
+test_description='Test git-stash'
+
+. ./test-lib.sh
+
+test_expect_success 'stash some dirty working directory' '
+       echo 1 > file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+       echo 2 > file &&
+       git add file &&
+       echo 3 > file &&
+       test_tick &&
+       git stash &&
+       git diff-files --quiet &&
+       git diff-index --cached --quiet HEAD
+'
+
+cat > expect << EOF
+diff --git a/file b/file
+index 0cfbf08..00750ed 100644
+--- a/file
++++ b/file
+@@ -1 +1 @@
+-2
++3
+EOF
+
+test_expect_success 'parents of stash' '
+       test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
+       git diff stash^2..stash > output &&
+       diff -u output expect
+'
+
+test_expect_success 'apply needs clean working directory' '
+       echo 4 > other-file &&
+       git add other-file &&
+       echo 5 > other-file
+       ! git stash apply
+'
+
+test_expect_success 'apply stashed changes' '
+       git add other-file &&
+       test_tick &&
+       git commit -m other-file &&
+       git stash apply &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_expect_success 'apply stashed changes (including index)' '
+       git reset --hard HEAD^ &&
+       echo 6 > other-file &&
+       git add other-file &&
+       test_tick &&
+       git commit -m other-file &&
+       git stash apply --index &&
+       test 3 = $(cat file) &&
+       test 2 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_done