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