From: Thomas Gummerer <t.gummerer@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>,
"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
sunny@sunbase.org, "Jakub Narębski" <jnareb@gmail.com>,
"Matthieu Moy" <Matthieu.Moy@grenoble-inp.fr>,
"Thomas Gummerer" <t.gummerer@gmail.com>
Subject: [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec
Date: Sat, 25 Feb 2017 21:33:04 +0000 [thread overview]
Message-ID: <20170225213306.2410-5-t.gummerer@gmail.com> (raw)
In-Reply-To: <20170225213306.2410-1-t.gummerer@gmail.com>
While working on a repository, it's often helpful to stash the changes
of a single or multiple files, and leave others alone. Unfortunately
git currently offers no such option. git stash -p can be used to work
around this, but it's often impractical when there are a lot of changes
over multiple files.
Allow 'git stash push' to take pathspec to specify which paths to stash.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
Documentation/git-stash.txt | 9 ++++-
git-stash.sh | 37 +++++++++++++------
t/t3903-stash.sh | 76 ++++++++++++++++++++++++++++++++++++++
t/t3905-stash-include-untracked.sh | 26 +++++++++++++
4 files changed, 136 insertions(+), 12 deletions(-)
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index d240df4af7..88369ed8b6 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -17,6 +17,7 @@ SYNOPSIS
[-u|--include-untracked] [-a|--all] [<message>]]
'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m|--message <message>]]
+ [--] [<pathspec>...]
'git stash' clear
'git stash' create [<message>]
'git stash' store [-m|--message <message>] [-q|--quiet] <commit>
@@ -48,7 +49,7 @@ OPTIONS
-------
save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
-push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>]::
+push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
Save your local modifications to a new 'stash' and roll them
back to HEAD (in the working tree and in the index).
@@ -58,6 +59,12 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q
only <message> does not trigger this action to prevent a misspelled
subcommand from making an unwanted stash.
+
+When pathspec is given to 'git stash push', the new stash records the
+modified states only for the files that match the pathspec. The index
+entries and working tree files are then rolled back to the state in
+HEAD only for these files, too, leaving files that do not match the
+pathspec intact.
++
If the `--keep-index` option is used, all changes already added to the
index are left intact.
+
diff --git a/git-stash.sh b/git-stash.sh
index ef5d1b45be..57828f926d 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -11,6 +11,7 @@ USAGE="list [<options>]
[-u|--include-untracked] [-a|--all] [<message>]]
or: $dashless push [--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m <message>]
+ [-- <pathspec>...]
or: $dashless clear"
SUBDIRECTORY_OK=Yes
@@ -35,15 +36,15 @@ else
fi
no_changes () {
- git diff-index --quiet --cached HEAD --ignore-submodules -- &&
- git diff-files --quiet --ignore-submodules &&
+ git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
+ git diff-files --quiet --ignore-submodules -- "$@" &&
(test -z "$untracked" || test -z "$(untracked_files)")
}
untracked_files () {
excl_opt=--exclude-standard
test "$untracked" = "all" && excl_opt=
- git ls-files -o -z $excl_opt
+ git ls-files -o -z $excl_opt -- "$@"
}
clear_stash () {
@@ -71,12 +72,16 @@ create_stash () {
shift
untracked=${1?"BUG: create_stash () -u requires an argument"}
;;
+ --)
+ shift
+ break
+ ;;
esac
shift
done
git update-index -q --refresh
- if no_changes
+ if no_changes "$@"
then
exit 0
fi
@@ -108,7 +113,7 @@ create_stash () {
# Untracked files are stored by themselves in a parentless commit, for
# ease of unpacking later.
u_commit=$(
- untracked_files | (
+ untracked_files "$@" | (
GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE &&
rm -f "$TMPindex" &&
@@ -131,7 +136,7 @@ create_stash () {
git read-tree --index-output="$TMPindex" -m $i_tree &&
GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE &&
- git diff-index --name-only -z HEAD -- >"$TMP-stagenames" &&
+ git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
git write-tree &&
rm -f "$TMPindex"
@@ -145,7 +150,7 @@ create_stash () {
# find out what the user wants
GIT_INDEX_FILE="$TMP-index" \
- git add--interactive --patch=stash -- &&
+ git add--interactive --patch=stash -- "$@" &&
# state of the working tree
w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
@@ -273,27 +278,37 @@ push_stash () {
die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")"
fi
+ test -n "$untracked" || git ls-files --error-unmatch -- "$@" >/dev/null || exit 1
+
git update-index -q --refresh
- if no_changes
+ if no_changes "$@"
then
say "$(gettext "No local changes to save")"
exit 0
fi
+
git reflog exists $ref_stash ||
clear_stash || die "$(gettext "Cannot initialize stash")"
- create_stash -m "$stash_msg" -u "$untracked"
+ create_stash -m "$stash_msg" -u "$untracked" -- "$@"
store_stash -m "$stash_msg" -q $w_commit ||
die "$(gettext "Cannot save the current status")"
say "$(eval_gettext "Saved working directory and index state \$stash_msg")"
if test -z "$patch_mode"
then
- git reset --hard ${GIT_QUIET:+-q}
+ if test $# != 0
+ then
+ git reset ${GIT_QUIET:+-q} -- "$@"
+ git checkout ${GIT_QUIET:+-q} HEAD -- $(git ls-files -z --modified "$@")
+ git clean --force ${GIT_QUIET:+-q} -d -- "$@"
+ else
+ git reset --hard ${GIT_QUIET:+-q}
+ fi
test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
if test -n "$untracked"
then
- git clean --force --quiet -d $CLEAN_X_OPTION
+ git clean --force --quiet -d $CLEAN_X_OPTION -- "$@"
fi
if test "$keep_index" = "t" && test -n "$i_tree"
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index ffe3549ea5..4d8a096773 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -802,4 +802,80 @@ test_expect_success 'create with multiple arguments for the message' '
test_cmp expect actual
'
+test_expect_success 'stash -- <pathspec> stashes and restores the file' '
+ >foo &&
+ >bar &&
+ git add foo bar &&
+ git stash push -- foo &&
+ test_path_is_file bar &&
+ test_path_is_missing foo &&
+ git stash pop &&
+ test_path_is_file foo &&
+ test_path_is_file bar
+'
+
+test_expect_success 'stash with multiple pathspec arguments' '
+ >foo &&
+ >bar &&
+ >extra &&
+ git add foo bar extra &&
+ git stash push -- foo bar &&
+ test_path_is_missing bar &&
+ test_path_is_missing foo &&
+ test_path_is_file extra &&
+ git stash pop &&
+ test_path_is_file foo &&
+ test_path_is_file bar &&
+ test_path_is_file extra
+'
+
+test_expect_success 'stash with file including $IFS character' '
+ >"foo bar" &&
+ >foo &&
+ >bar &&
+ git add foo* &&
+ git stash push -- "foo b*" &&
+ test_path_is_missing "foo bar" &&
+ test_path_is_file foo &&
+ test_path_is_file bar &&
+ git stash pop &&
+ test_path_is_file "foo bar" &&
+ test_path_is_file foo &&
+ test_path_is_file bar
+'
+
+test_expect_success 'stash push -p with pathspec shows no changes only once' '
+ >foo &&
+ git add foo &&
+ git commit -m "tmp" &&
+ git stash push -p foo >actual &&
+ echo "No local changes to save" >expect &&
+ git reset --hard HEAD~ &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stash push with pathspec shows no changes when there are none' '
+ >foo &&
+ git add foo &&
+ git commit -m "tmp" &&
+ git stash push foo >actual &&
+ echo "No local changes to save" >expect &&
+ git reset --hard HEAD~ &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stash push with pathspec not in the repository errors out' '
+ >untracked &&
+ test_must_fail git stash push untracked &&
+ test_path_is_file untracked
+'
+
+test_expect_success 'untracked files are left in place when -u is not given' '
+ >file &&
+ git add file &&
+ >untracked &&
+ git stash push file &&
+ test_path_is_file untracked
+'
+
test_done
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index f372fc8ca8..193adc7b68 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -185,4 +185,30 @@ test_expect_success 'stash save --all is stash poppable' '
test -s .gitignore
'
+test_expect_success 'stash push --include-untracked with pathspec' '
+ >foo &&
+ >bar &&
+ git stash push --include-untracked -- foo &&
+ test_path_is_file bar &&
+ test_path_is_missing foo &&
+ git stash pop &&
+ test_path_is_file bar &&
+ test_path_is_file foo
+'
+
+test_expect_success 'stash push with $IFS character' '
+ >"foo bar" &&
+ >foo &&
+ >bar &&
+ git add foo* &&
+ git stash push --include-untracked -- "foo b*" &&
+ test_path_is_missing "foo bar" &&
+ test_path_is_file foo &&
+ test_path_is_file bar &&
+ git stash pop &&
+ test_path_is_file "foo bar" &&
+ test_path_is_file foo &&
+ test_path_is_file bar
+'
+
test_done
--
2.11.0.301.g275aeb250c.dirty
next prev parent reply other threads:[~2017-02-25 20:29 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <mailto:20170205202642.14216-1-t.gummerer@gmail.com>
2017-02-12 21:54 ` [PATCH v4 0/7] stash: support pathspec argument Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 1/7] Documentation/stash: remove mention of git reset --hard Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 2/7] stash: introduce push verb Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 3/7] stash: add test for the create command line arguments Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 4/7] stash: introduce new format create Thomas Gummerer
[not found] ` <vpqefz0ohub.fsf@anie.imag.fr>
2017-02-14 21:40 ` Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 5/7] stash: teach 'push' (and 'create') to honor pathspec Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 6/7] stash: use stash_push for no verb form Thomas Gummerer
2017-02-12 21:54 ` [PATCH v4 7/7] stash: allow pathspecs in the " Thomas Gummerer
2017-02-12 22:07 ` [PATCH v4 0/7] stash: support pathspec argument Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 0/6] " Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 1/6] stash: introduce push verb Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 2/6] stash: add test for the create command line arguments Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 3/6] stash: refactor stash_create Thomas Gummerer
2017-02-17 23:48 ` Jeff King
2017-02-19 9:17 ` Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 5/6] stash: use stash_push for no verb form Thomas Gummerer
2017-02-17 22:41 ` [PATCH v5 6/6] stash: allow pathspecs in the " Thomas Gummerer
2017-02-17 23:46 ` Jeff King
2017-02-19 9:18 ` Thomas Gummerer
2017-02-17 23:01 ` [PATCH v5 0/6] stash: support pathspec argument Junio C Hamano
2017-02-17 23:12 ` Thomas Gummerer
2017-02-17 23:14 ` Junio C Hamano
[not found] ` <xmqqr32wph97.fsf@gitster.mtv.corp.google.com>
2017-02-17 23:06 ` Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 " Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 1/6] stash: introduce push verb Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 2/6] stash: add test for the create command line arguments Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 3/6] stash: refactor stash_create Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec Thomas Gummerer
2017-02-21 16:55 ` Junio C Hamano
2017-02-25 20:27 ` Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 5/6] stash: use stash_push for no verb form Thomas Gummerer
2017-02-19 11:03 ` [PATCH v6 6/6] stash: allow pathspecs in the " Thomas Gummerer
2017-02-20 7:57 ` [PATCH v6 0/6] stash: support pathspec argument Jeff King
2017-02-20 8:22 ` Junio C Hamano
2017-02-20 19:39 ` Junio C Hamano
2017-02-25 15:57 ` Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 " Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 1/6] stash: introduce push verb Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 2/6] stash: add test for the create command line arguments Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 3/6] stash: refactor stash_create Thomas Gummerer
2017-02-25 21:33 ` Thomas Gummerer [this message]
2017-02-27 20:32 ` [PATCH v7 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec Junio C Hamano
2017-02-27 20:35 ` Junio C Hamano
2017-02-27 21:56 ` Thomas Gummerer
2017-02-27 22:58 ` Junio C Hamano
2017-02-27 21:09 ` Junio C Hamano
2017-02-27 21:53 ` Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 5/6] stash: use stash_push for no verb form Thomas Gummerer
2017-02-25 21:33 ` [PATCH v7 6/6] stash: allow pathspecs in the " Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 0/6] stash: support pathspec argument Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 1/6] stash: introduce push verb Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 2/6] stash: add test for the create command line arguments Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 3/6] stash: refactor stash_create Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 4/6] stash: teach 'push' (and 'create_stash') to honor pathspec Thomas Gummerer
2017-02-28 22:15 ` Junio C Hamano
2017-03-01 21:57 ` Thomas Gummerer
2017-03-01 22:43 ` Junio C Hamano
2017-02-28 20:33 ` [PATCH v8 5/6] stash: use stash_push for no verb form Thomas Gummerer
2017-02-28 20:33 ` [PATCH v8 6/6] stash: allow pathspecs in the " Thomas Gummerer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170225213306.2410-5-t.gummerer@gmail.com \
--to=t.gummerer@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=Matthieu.Moy@grenoble-inp.fr \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jnareb@gmail.com \
--cc=peff@peff.net \
--cc=sunny@sunbase.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).