git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH/RFC] stash: introduce 'stash save --keep-index' option

From
SZEDER Gábor <szeder@ira.uka.de>
Date
Jun 27, 2008, 14:37 UTC
Message-ID
<20080627143715.GD6747@neumann>
In-Reply-To
<20080627071014.GA12344@atjola.homenet>

'git stash save' saves local modifications to a new stash, and runs 'git reset --hard' to revert them to a clean index and work tree. When the '--keep-index' option is specified, after that 'git reset --hard' the previous contents of the index is restored and the work tree is updated to match the index. This option is useful if the user wants to commit only parts of his local modifications, but wants to test those parts before committing.

Also add support for the completion of the new option, and add an example use case to the documentation.

Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
---
On Fri, Jun 27, 2008 at 09:10:14AM +0200, Björn Steinbrink wrote:
Show 14 quoted lines
> Hm, I use "stash" for that purpose, which leads to kind of the reverse
> of your approach. So I do sth. like this:
> 
>  - hack hack hack
>  - Notice that I want to make two commits out of what I have in my
>    working tree
>  - git add -p -- stage what I want in the first commit
>  - git commit -m tmp -- temporary commit
>  - git stash -- stash away what doesn't belong in the first commit
>  - git reset HEAD^ -- drop the temporary commit, with the changes kept
>    in the working tree
>  - test, fix bugs, read the diff, whatever
>  - git commit -- this time for good
>  - git stash apply -- get back the changes for the second commit

I used to do the same, so I have added a '--keep-index' option to 'git stash save' to simplify this workflow. Have a look at the use case added to the documentation to see, how you could spare the temporary commit and the 'reset HEAD^'.

RFC, because I'm not quite confident with using plumbing like 'git read-tree'... and there are no tests.

 Documentation/git-stash.txt            |   22 +++++++++++++++++++++-
 contrib/completion/git-completion.bash |   13 ++++++++++++-
 git-stash.sh                           |   22 ++++++++++++++++++----
 3 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index baa4f55..936864f 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -36,12 +36,15 @@ is also possible).
 OPTIONS
 -------
 
-save [<message>]::
+save [--keep-index] [<message>]::
 
 	Save your local modifications to a new 'stash', and run `git-reset
 	--hard` to revert them.  This is the default action when no
 	subcommand is given. The <message> part is optional and gives
 	the description along with the stashed state.
++
+If the `--keep-index` option is used, all changes already added to the
+index are left intact.
 
 list [<options>]::
 
@@ -169,6 +172,23 @@ $ git stash apply
 ... continue hacking ...
 ----------------------------------------------------------------
 
+Testing partial commits::
+
+You can use `git stash save --keep-index` when you want to make two or
+more commits out of the changes in the work tree, and you want to test
+each change before committing:
++
+----------------------------------------------------------------
+... hack hack hack ...
+$ git add --patch foo
+$ git stash save --keep-index
+$ build && run tests
+$ git commit -m 'First part'
+$ git stash apply
+$ build && run tests
+$ git commit -a -m 'Second part'
+----------------------------------------------------------------
+
 SEE ALSO
 --------
 linkgit:git-checkout[1],
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ebf7cde..9a15500 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1139,8 +1139,19 @@ _git_show ()
 _git_stash ()
 {
 	local subcommands='save list show apply clear drop pop create'
-	if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
+	local subcommand="$(__git_find_subcommand "$subcommands")"
+	if [ -z "$subcommand" ]; then
 		__gitcomp "$subcommands"
+	else
+		local cur="${COMP_WORDS[COMP_CWORD]}"
+		case "$subcommand,$cur" in
+		save,--*)
+			__gitcomp "--keep-index"
+			;;
+		*)
+			COMPREPLY=()
+			;;
+		esac
 	fi
 }
 
diff --git a/git-stash.sh b/git-stash.sh
index 4938ade..92531a2 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -86,6 +86,13 @@ create_stash () {
 }
 
 save_stash () {
+	keep_index=
+	case "$1" in
+	--keep-index)
+		keep_index=t
+		shift
+	esac
+
 	stash_msg="$1"
 
 	if no_changes
@@ -104,6 +111,13 @@ save_stash () {
 	git update-ref -m "$stash_msg" $ref_stash $w_commit ||
 		die "Cannot save the current status"
 	printf 'Saved working directory and index state "%s"\n' "$stash_msg"
+
+	git reset --hard
+
+	if test -n "$keep_index" && test -n $i_tree
+	then
+		git read-tree --reset -u $i_tree
+	fi
 }
 
 have_stash () {
@@ -153,7 +167,8 @@ apply_stash () {
 		die "$*: no valid stashed state found"
 
 	unstashed_index_tree=
-	if test -n "$unstash_index" && test "$b_tree" != "$i_tree"
+	if test -n "$unstash_index" && test "$b_tree" != "$i_tree" &&
+			test "$c_tree" != "$i_tree"
 	then
 		git diff-tree --binary $s^2^..$s^2 | git apply --cached
 		test $? -ne 0 &&
@@ -235,7 +250,7 @@ show)
 	;;
 save)
 	shift
-	save_stash "$*" && git-reset --hard
+	save_stash "$*"
 	;;
 apply)
 	shift
@@ -268,8 +283,7 @@ pop)
 	if test $# -eq 0
 	then
 		save_stash &&
-		echo '(To restore them type "git stash apply")' &&
-		git-reset --hard
+		echo '(To restore them type "git stash apply")'
 	else
 		usage
 	fi
-- 
1.5.6.1.95.ge713
Previous: Björn SteinbrinkNext: Junio C Hamano
Message 3 of 57 in “An alternate model for preparing partial commits”
  1. Robert AndersonJun 27, 2008
  2. Björn SteinbrinkJun 27, 2008
  3. stash: introduce 'stash save --keep-index' optionSZEDER Gábor, Jun 27, 2008
  4. Junio C HamanoJun 27, 2008
  5. Robert AndersonJun 27, 2008
  6. Björn SteinbrinkJun 27, 2008
  7. Robert AndersonJun 27, 2008
  8. Johannes SixtJun 27, 2008
  9. Robert AndersonJun 27, 2008
  10. Petr BaudisJun 27, 2008
  11. Robert AndersonJun 27, 2008
  12. Johannes SchindelinJun 27, 2008
  13. Miklos VajnaJun 27, 2008
  14. Robert AndersonJun 27, 2008
  15. Johannes SchindelinJun 27, 2008
  16. Robert AndersonJun 27, 2008
  17. Dana HowJun 27, 2008
  18. Stephen SinclairJun 27, 2008
  19. David JeskeJun 27, 2008
  20. David JeskeAug 13, 2016
  21. Wincent ColaiutaJun 28, 2008
  22. Dmitry PotapovJun 28, 2008
  23. Robert AndersonJun 28, 2008
  24. Dmitry PotapovJun 28, 2008
  25. Junio C HamanoJun 27, 2008
  26. Robert AndersonJun 27, 2008
  27. Jeff KingJun 28, 2008
  28. Robert AndersonJun 28, 2008
  29. Jeff KingJun 28, 2008
  30. Junio C HamanoJun 28, 2008
  31. Johannes SchindelinJun 28, 2008
  32. Jeff KingJul 8, 2008
  33. David JeskeJun 27, 2008
  34. Jakub NarebskiJun 27, 2008
  35. David JeskeJun 27, 2008
  36. David JeskeAug 13, 2016
  37. David JeskeAug 13, 2016
  38. Robert AndersonJun 27, 2008
  39. Robert AndersonJun 27, 2008
  40. Junio C HamanoJun 27, 2008
  41. Robert AndersonJun 28, 2008
  42. Dmitry PotapovJun 28, 2008
  43. Robert AndersonJun 28, 2008
  44. Stephen SinclairJun 28, 2008
  45. Robert AndersonJun 28, 2008
  46. Robert AndersonJun 28, 2008
  47. Jakub NarebskiJun 28, 2008
  48. Robert AndersonJun 28, 2008
  49. David JeskeJun 28, 2008
  50. David JeskeAug 13, 2016
  51. Stephen SinclairJun 28, 2008
  52. David JeskeJun 28, 2008
  53. David JeskeAug 13, 2016
  54. Fwd: An alternate model for preparing partial commitsRobert Anderson, Jun 28, 2008
  55. Dmitry PotapovJun 28, 2008
  56. Robert AndersonJun 28, 2008
  57. Dmitry PotapovJun 28, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.