Subject: [PATCH] git-stash: add flag to skip "git reset --hard"

From: Tom Anderson <[email-masked]>
Date: Sun, 1 May 2016 14:57:18 -0700

Add the "--no-reset" (same as "-r") flag to git-stash.sh.  A common
workflow is to use "git-stash save" and "git-stash apply" to save your
work without modifying your changed files.  This forces users to
reload their changed files in text editors like emacs, and touches the
modify time on all changed files, potentially making incremental
builds slower if many files in the build depend on your changed files.

Add documentation in Documentation/git-stash.txt and tests in
t/t3903-stash.sh.

Signed-off-by: Thomas Anderson <[email-masked]>
---
  Documentation/git-stash.txt |  9 ++++++---
  git-stash.sh                | 15 ++++++++++-----
  t/t3903-stash.sh            | 27 +++++++++++++++++++++++++++
  3 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 92df596..ba5ecf2 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -13,8 +13,8 @@ SYNOPSIS
  'git stash' drop [-q|--quiet] [<stash>]
  'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
  'git stash' branch <branchname> [<stash>]
-'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
-	     [-u|--include-untracked] [-a|--all] [<message>]]
+'git stash' [save [-p|--patch] [-r|--no-reset] [-k|--[no-]keep-index]
+	     [-q|--quiet] [-u|--include-untracked] [-a|--all] [<message>]]
  'git stash' clear
  'git stash' create [<message>]
  'git stash' store [-m|--message <message>] [-q|--quiet] <commit>
@@ -44,7 +44,7 @@ is also possible).
  OPTIONS
  -------
  -save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] 
[-a|--all] [-q|--quiet] [<message>]::
+save [-p|--patch] [-r|--no-reset] [-k|--[no-]keep-index] 
[-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
   	Save your local modifications to a new 'stash', and run `git reset
  	--hard` to revert them.  The <message> part is optional and gives
@@ -61,6 +61,9 @@ stashed and then cleaned up with `git clean`, leaving 
the working directory
  in a very clean state. If the `--all` option is used instead then the
  ignored files are stashed and cleaned in addition to the untracked files.
  +
+If the `--no-reset` option is used, `git reset --hard` is skipped and the
+`--[no-]keep-index`, `--include-untracked`, and `--all` flags are ignored.
++
  With `--patch`, you can interactively select hunks from the diff
  between HEAD and the working tree to be stashed.  The stash entry is
  constructed such that its index state is the same as the index state
diff --git a/git-stash.sh b/git-stash.sh
index c7c65e2..aebebb0 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -7,8 +7,9 @@ USAGE="list [<options>]
     or: $dashless drop [-q|--quiet] [<stash>]
     or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
     or: $dashless branch <branchname> [<stash>]
-   or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
-		       [-u|--include-untracked] [-a|--all] [<message>]]
+   or: $dashless [save [--patch] [-r|--no-reset] [-k|--[no-]keep-index]
+		       [-q|--quiet] [-u|--include-untracked] [-a|--all]
+		       [<message>]]
     or: $dashless clear"
   SUBDIRECTORY_OK=Yes
@@ -194,9 +195,13 @@ save_stash () {
  	keep_index=
  	patch_mode=
  	untracked=
+	no_reset=
  	while test $# != 0
  	do
  		case "$1" in
+		-r|--no-reset)
+			no_reset=t
+			;;
  		-k|--keep-index)
  			keep_index=t
  			;;
@@ -268,7 +273,7 @@ save_stash () {
  	die "$(gettext "Cannot save the current status")"
  	say Saved working directory and index state "$stash_msg"
  -	if test -z "$patch_mode"
+	if test -z "$patch_mode" -a -z "$no_reset"
  	then
  		git reset --hard ${GIT_QUIET:+-q}
  		test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
@@ -276,12 +281,12 @@ save_stash () {
  		then
  			git clean --force --quiet -d $CLEAN_X_OPTION
  		fi
-
  		if test "$keep_index" = "t" && test -n $i_tree
  		then
  			git read-tree --reset -u $i_tree
  		fi
-	else
+	elif -n "$patch_mode"
+	then
  		git apply -R < "$TMP-patch" ||
  		die "$(gettext "Cannot remove worktree changes")"
  diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 2142c1f..3eba19a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -248,6 +248,33 @@ test_expect_success 'stash --no-keep-index' '
  	test bar,bar2 = $(cat file),$(cat file2)
  '
  +test_expect_success 'stash -r' '
+	git reset &&
+	echo foo420 > file &&
+	echo bar420 > file2 &&
+	git add file2 &&
+	git stash -r &&
+	test foo420,bar420 = $(cat file),$(cat file2)
+'
+
+test_expect_success 'stash --no-reset' '
+	git reset &&
+	echo bar33 > file &&
+	echo bar44 > file2 &&
+	git add file2 &&
+	git stash --no-reset &&
+	test bar33,bar44 = $(cat file),$(cat file2)
+'
+
+test_expect_success 'stash -r with ignored options -k -u -a' '
+	git reset &&
+	echo foo55 > file &&
+	echo bar66 > file2 &&
+	git add file2 &&
+	git stash -r &&
+	test foo55,bar66 = $(cat file),$(cat file2)
+'
+
  test_expect_success 'stash --invalid-option' '
  	echo bar5 > file &&
  	echo bar6 > file2 &&
-- 
2.8.0.rc2