Subject: Re: [FEATURE] Proposal: git stash --only-unstaged

From: Junio C Hamano <[email-masked]>
Date: Sun, 17 Aug 2025 09:08:38 -0700

Phillip Wood <[email-masked]> writes:

> To use it create your stash with "git stash push --keep-index" and then
> use the script to pop the unstaged changes rather than using "git stash
> pop". If the script proves to be useful then perhaps we could add an
> "--unstaged" option to "git stash pop"

Hmph, would the behaviour useful enough that it should be always
enabled, without any new option?  I strongly suspect that those who
worked on adding "--keep-index" option did not expect the user to be
mucking with the working tree files while "testing the staged stuff
by updating the working tree files to match it and nothing else",
and as long as the end-user stays within that originally designed
use case, nothing changes for them, no?

Thanks.

(the script left for reference without comments below).

> ---- 8< ----
> #!/bin/sh
>
> USAGE="${0##*/} [<stash>]"
> SUBDIRECTORY_OK=1
> . "$(git --exec-path)/git-sh-setup"
> cd_to_toplevel
> require_clean_work_tree stash-pop-unstaged
>
> LF='
> '
> stash="${1:-stash@{0}}"
> if ! stash_oid="$(git rev-parse --verify --quiet "$stash")" ||
>    ! oid1="$(git rev-parse --verify --quiet $stash_oid^1)" ||
>    ! oid2="$(git rev-parse $stash_oid^2^@ 2>/dev/null)" ||
>    test "$oid1" != "$oid2"
> then
>     die "error: '$stash' does not look like a stash commit"
> fi
> merge_output="$(git merge-tree --merge-base=$stash_oid^2: HEAD: $stash_oid:)"
> status=$?
> if test $status = 0
> then
>     tree=$merge_output
>     conflict_info=
>     messages=
> elif test $status = 1
> then
>     merge_output="$merge_output$LF"
>     tree="${merge_output%%$LF*}"
>     conflict_info="${merge_output%%$LF$LF*}"
>     conflict_info="${conflict_info#*$LF}"
>     messages="${merge_output#*$LF$LF}"
> else
>     exit 128
> fi
> git read-tree --index-output="$GIT_DIR/stash-pop-index" -m -u HEAD $tree &&
> rm "$GIT_DIR/stash-pop-index" &&
> if test -n "$conflict_info"
> then
>     printf '%s' "$messages" >&2
>     printf '%s\n' "$conflict_info" | git update-index --index-info
> else
>     git stash drop "$stash"
> fi