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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 13/08/2025 09:51, J. Dettweiler wrote:

**Current limitations:**
- `git stash --keep-index` still saves the index in the stash object.
- When I later `git stash pop`, Git tries to restore those staged changes, often causing merge conflicts if I’ve modified them during the test.

As the index and the worktree are saved in the stash we can restore the
unstaged changes with a three-way merge between the stashed index, HEAD
and the stashed worktree. The (lightly tested) script below does that
and updates the worktree without changing the index unless there are
conflicts. There will only be conflicts when a staged line that is
adjacent to an unstaged line is changed. Changes to staged lines that
are not next to unstaged lines should not create conflicts as they are
only modified on one side of the merge.

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"

Thanks

Phillip

---- 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





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux