# [DRAFT] Create stash from index state

2 messages from 2009-02-14 to 2009-02-14. Participants: Adeodato Simó, Johannes Schindelin.
Thread: https://gitlist.dev/t/17796

## Adeodato Simó, 2009-02-14 22:39

Subject: [DRAFT] Create stash from index state
Message-ID: <20090214223929.GA29472@chistera.yi.org>
URL: https://gitlist.dev/e/20090214223929.GA29472%40chistera.yi.org

```
Hello,

I've always missed a way to do what `bzr shelve` does: interactive
stash, where you just select hunks à-la `add -p`, and then those gets
stashed away.

I've recently realized that git-stash doesn't need to know how to prompt
for changes, and that just a --from-index flag that would stash the
state of the index would be simpler and (at least in my eyes) very git-ish.

Do you think such a flag would be appropriate? I've prepared a
preliminary, but I need help with the part that removes the index
changes from the working tree (a partial git-reset --hard). I know
"checkout stash && checkout -" would do it, but I really don't know how
to do that with low-level plumbing (unless git-checkout is actually okay
for this.) Any suggestions?

Additionally, I have two behaviors I'd like in stash: the ability to
apply/pop on top of a dirty state, perhaps with a -f flag (at the moment
I'm just doing `commit -a -m foo && pop && reset HEAD^`), and the
ability to --amend the last stash state, as in "oh, add this to the last
stash please". Thoughts?

Many thanks in advance,

-- 
Adeodato Simó                                     dato at net.com.org.es
Debian Developer                                  adeodato at debian.org
 
When all is summed up, a man never speaks of himself without loss; his
accusations of himself are always believed; his praises never.
                -- Michel de Montaigne


diff --git a/git-stash.sh b/git-stash.sh
index b9ace99..0b6f5bd 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -67,26 +67,32 @@ create_stash () {
 		git commit-tree $i_tree -p $b_commit) ||
 		die "Cannot save the current index state"
 
-	# state of the working tree
-	w_tree=$( (
-		rm -f "$TMP-index" &&
-		cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" &&
-		GIT_INDEX_FILE="$TMP-index" &&
-		export GIT_INDEX_FILE &&
-		git read-tree -m $i_tree &&
-		git add -u &&
-		git write-tree &&
-		rm -f "$TMP-index"
-	) ) ||
-		die "Cannot save the current worktree state"
-
-	# create the stash
 	if test -z "$stash_msg"
 	then
 		stash_msg=$(printf 'WIP on %s' "$msg")
 	else
 		stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
 	fi
+
+	if test -z "$from_index"
+	then
+		# state of the working tree
+		w_tree=$( (
+			rm -f "$TMP-index" &&
+			cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" &&
+			GIT_INDEX_FILE="$TMP-index" &&
+			export GIT_INDEX_FILE &&
+			git read-tree -m $i_tree &&
+			git add -u &&
+			git write-tree &&
+			rm -f "$TMP-index"
+		) ) ||
+			die "Cannot save the current worktree state"
+	else
+		w_tree="$i_tree"
+	fi
+
+	# create the stash
 	w_commit=$(printf '%s\n' "$stash_msg" |
 		git commit-tree $w_tree -p $b_commit -p $i_commit) ||
 		die "Cannot record working tree state"
@@ -94,10 +100,22 @@ create_stash () {
 
 save_stash () {
 	keep_index=
+	from_index=
 	case "$1" in
 	--keep-index)
 		keep_index=t
 		shift
+		if [ "$1" = "--from-index" ]; then
+			die "--keep-index and --from-index are incompatible"
+		fi
+		;;
+	--from-index)
+		from_index=t
+		shift
+		if [ "$1" = "--keep-index" ]; then
+			die "--from-index and --keep-index are incompatible"
+		fi
+		;;
 	esac
 
 	stash_msg="$*"
@@ -120,7 +138,14 @@ save_stash () {
 		die "Cannot save the current status"
 	printf 'Saved working directory and index state "%s"\n' "$stash_msg"
 
-	git reset --hard
+	if test -z "$from_index"
+	then
+		git reset --hard
+	else
+		# XXX Use plumbing. How?
+		git checkout stash
+		git checkout -
+	fi
 
 	if test -n "$keep_index" && test -n $i_tree
 	then

```

## Johannes Schindelin, 2009-02-14 22:59

Subject: Re: [DRAFT] Create stash from index state
Message-ID: <alpine.DEB.1.00.0902142356200.10279@pacific.mpi-cbg.de>
URL: https://gitlist.dev/e/alpine.DEB.1.00.0902142356200.10279%40pacific.mpi-cbg.de
In-Reply-To: <20090214223929.GA29472@chistera.yi.org>

```
Hi,

On Sat, 14 Feb 2009, Adeodato Simó wrote:

> I've always missed a way to do what `bzr shelve` does: interactive
> stash, where you just select hunks à-la `add -p`, and then those gets
> stashed away.

I recently wrote this in my blog:

-- snip --
I think something like an interactive stash is needed. A method to 
specify what you want to keep in the working directory, the rest should 
be stashed. The idea would be something like this:

   1. Add the desired changes into a temporary index.
   2. Put the rest of the changes in another temporary index.
   3. Stash the latter index.
   4. Synchronize the working directory with the first index.
   5. Clean up temporary indices. 

Or in code:

$ cp .git/index .git/interactive-stash-1
$ GIT_INDEX_FILE=.git/interactive-stash-1 git add -i
$ cp .git/index .git/interactive-stash-2
$ GIT_INDEX_FILE=.git/interactive-stash-1 git diff -R |
        (GIT_INDEX_FILE=.git/interactive-stash-2 git apply--index)
$ tree=$(GIT_INDEX_FILE=.git/index git write-tree)
$ commit=$(echo Current index | git commit-tree $tree -p HEAD)
$ tree=$(GIT_INDEX_FILE=.git/interactive-stash-2 git write-tree)
$ commit=$(echo Edited out | git commit-tree $tree -p HEAD -p $commit)
$ git update-ref refs/stash $commit
$ GIT_INDEX_FILE=.git/interactive-stash-1 git checkout-index -a -f
$ rm .git/interactive-stash-1 .git/interactive-stash-2

This should probably go into git-stash.sh, maybe even with a switch to 
start git-gui to do the interactive adding instead of git-add.
-- snap --

Now, the main reason I did not implement this already is that I am not 
quite sure if you should select the changes you _want_ to keep (which 
would seem the more natural way to say what needs stashing), or if it 
would be better to select the changes you do _not_ want to keep (this 
would seem more consistent, as "git add -i" is about selecting what goes 
into the index, so "git stash -i" should be about selecting what goes into 
the stash).

Maybe you want to give it a try?

Ciao,
Dscho

```
