Here's a little script I've come up with in the past to do exactly this:
(Note: I originally posted this at https://stackoverflow.com/a/17137669/531021, but it seems to apply here as well. These aren't exactly duplicate questions, so I think it serves as a possible answer in both cases)
#!/bin/sh
# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`
# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`
# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`
# get back to a clean state with no changes, staged or otherwise
git reset -q --hard
# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to suceed
git cherry-pick -n $INDEXCOMMIT
git stash
# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT
CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
# If there are no conflicts, it's safe to reset, so that
# any previously unstaged changes remain unstaged
#
# However, if there are conflicts, then we don't want to reset the files
# and lose the merge/conflict info.
git reset -q
fi
You can save the above script as git-stash-index
somewhere on your path, and can then invoke it as git stash-index
# <hack hack hack>
git add <files that you want to stash>
git stash-index
Now the stash contains a new entry that only contains the changes you had staged, and your working tree still contains any unstaged changes.
The main gotcha is that you may not be able to cleanly remove the indexed changes without causing conflicts, e.g. if the working tree contains changes that depend on the indexed changes.
In this case, any such conflicts will be left in the usual unmerged conflict state, similarly to after a cherry-pick/merge.
e.g.
git init
echo blah >> "blah"
git add -A
git commit -m "blah"
echo "another blah" >> blah
git add -A
echo "yet another blah" >> blah
# now HEAD contains "blah", the index contains "blah\nanother blah"
# and the working tree contains "blah\nanother blah\nyetanother blah"
git stash-index
# A new stash is created containing "blah\nanother blah", and we are
# left with a merge conflict, which can be resolved to produce
# "blah\nyet another blah"