[PATCH v4 0/7] stash: support pathspec argument
From: Thomas Gummerer <hidden>
Date: 2017-02-12 21:54:27
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
Thanks Peff and Junio for the review of the last round.
Changes since v3:
- Instead of using ${1-...} to check for missing arguments and dying
show the usage for stash instead, being more consistent with how the
rest of stash behaves
- Let push_stash handle the --help argument from save_stash as well,
passing it through directly.
- Fix the tests to not pipe the output to something, and thereby
swallowing the error codes
- Update the commit message in 4/7 to acknowledge that there is a
small regression between the two versions
- Correctly detect when there are no changes, and only show the
message once
- Fix the accidental deletion of untracked files when a pathspec is
used. Also added test cases for that.
- Add documentation for git stash push to the usage text
- Respect the -q flag and the GIT_QUIET environment variable
- This also adds two new patches, one using push_stash instead of
save_stash for git stash without any verb. The other allows using a
pathspec in the verb-less option of git stash.
Interdiff below:diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index be55e456fa..b0825f4aca 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt@@ -13,15 +13,15 @@ SYNOPSIS 'git stash' drop [-q|--quiet] [<stash>] 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>] 'git stash' branch <branchname> [<stash>] -'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] - [-u|--include-untracked] [-a|--all] [<message>]] -'git stash' push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] +'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] + [-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>...] + [--] [<pathspec>...]] 'git stash' clear 'git stash' create [<message>] 'git stash' create [-m <message>] [-u|--include-untracked <untracked|all>] - [-- <paths>...] + [-- <pathspec>...] 'git stash' store [-m|--message <message>] [-q|--quiet] <commit> DESCRIPTION
diff --git a/git-stash.sh b/git-stash.sh
index 46367d40aa..a184b1e274 100755
--- a/git-stash.sh
+++ b/git-stash.sh@@ -7,8 +7,11 @@ USAGE="list [<options>] or: $dashless drop [-q|--quiet] [<stash>] or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>] or: $dashless branch <branchname> [<stash>] - or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] - [-u|--include-untracked] [-a|--all] [<message>]] + or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet] + [-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
@@ -33,8 +36,8 @@ 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)") }
@@ -64,11 +67,13 @@ create_stash () { case "$1" in -m|--message) shift - stash_msg=${1?"-m needs an argument"} + test -z ${1+x} && usage + stash_msg="$1" new_style=t ;; -u|--include-untracked) shift + test -z ${1+x} && usage untracked="$1" new_style=t ;;
@@ -104,14 +109,11 @@ create_stash () { if test -z "$new_style" then stash_msg="$*" - while test $# != 0 - do - shift - done + set -- fi git update-index -q --refresh - if no_changes + if no_changes "$@" then exit 0 fi
@@ -270,7 +272,8 @@ push_stash () { ;; -m|--message) shift - stash_msg=${1?"-m needs an argument"} + test -z ${1+x} && usage + stash_msg=$1 ;; --help) show_help
@@ -308,7 +311,7 @@ push_stash () { fi git update-index -q --refresh - if no_changes + if no_changes "$@" then say "$(gettext "No local changes to save")" exit 0
@@ -325,9 +328,23 @@ push_stash () { then if test $# != 0 then - git ls-files -z -- "$@" | xargs -0 git reset -- - git ls-files -z --modified -- "$@" | xargs -0 git checkout HEAD -- - git ls-files -z --others -- "$@" | xargs -0 git clean --force -- + saved_untracked= + if test -n "$(git ls-files --others -- "$@")" + then + saved_untracked=$( + git ls-files -z --others -- "$@" | + xargs -0 git stash create -u all --) + fi + git ls-files -z -- "$@" | xargs -0 git reset ${GIT_QUIET:+-q} -- + git ls-files -z --modified -- "$@" | xargs -0 git checkout ${GIT_QUIET:+-q} HEAD -- + if test -n "$(git ls-files -z --others -- "$@")" + then + git ls-files -z --others -- "$@" | xargs -0 git clean --force -d ${GIT_QUIET:+-q} -- + fi + if test -n "$saved_untracked" + then + git stash pop -q $saved_untracked + fi else git reset --hard ${GIT_QUIET:+-q} fi
@@ -357,9 +374,6 @@ save_stash () { while test $# != 0 do case "$1" in - --help) - show_help - ;; --) shift break
@@ -685,17 +699,18 @@ apply_to_branch () { } PARSE_CACHE='--not-parsed' -# The default command is "save" if nothing but options are given +# The default command is "push" if nothing but options are given seen_non_option= for opt do case "$opt" in + --) break ;; -*) ;; *) seen_non_option=t; break ;; esac done -test -n "$seen_non_option" || set "save" "$@" +test -n "$seen_non_option" || set "push" "$@" # Main command set case "$1" in
@@ -746,7 +761,7 @@ branch) *) case $# in 0) - save_stash && + push_stash && say "$(gettext "(To restore them type \"git stash apply\")")" ;; *)
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 461fe46045..22ac75377b 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh@@ -274,9 +274,7 @@ test_expect_success 'stash --invalid-option' ' git add file2 && test_must_fail git stash --invalid-option && test_must_fail git stash save --invalid-option && - test bar5,bar6 = $(cat file),$(cat file2) && - git stash -- -message-starting-with-dash && - test bar,bar2 = $(cat file),$(cat file2) + test bar5,bar6 = $(cat file),$(cat file2) ' test_expect_success 'stash an added file' '
@@ -780,7 +778,7 @@ test_expect_success 'push -m shows right message' ' git add foo && git stash push -m "test message" && echo "stash@{0}: On master: test message" >expect && - git stash list | head -n 1 >actual && + git stash list -1 >actual && test_cmp expect actual '
@@ -789,7 +787,7 @@ test_expect_success 'create stores correct message' ' git add foo && STASH_ID=$(git stash create "create test message") && echo "On master: create test message" >expect && - git show --pretty=%s ${STASH_ID} | head -n1 >actual && + git show --pretty=%s -s ${STASH_ID} >actual && test_cmp expect actual '
@@ -798,7 +796,7 @@ test_expect_success 'create with multiple arguments for the message' ' git add foo && STASH_ID=$(git stash create test untracked) && echo "On master: test untracked" >expect && - git show --pretty=%s ${STASH_ID} | head -n1 >actual && + git show --pretty=%s -s ${STASH_ID} >actual && test_cmp expect actual '
@@ -807,7 +805,7 @@ test_expect_success 'new style stash create stores correct message' ' git add foo && STASH_ID=$(git stash create -m "create test message new style") && echo "On master: create test message new style" >expect && - git show --pretty=%s ${STASH_ID} | head -n1 >actual && + git show --pretty=%s -s ${STASH_ID} >actual && test_cmp expect actual '
@@ -839,18 +837,63 @@ test_expect_success 'stash with multiple filename arguments' ' ' test_expect_success 'stash with file including $IFS character' ' - >"foo bar" && + >"foo bar" && >foo && - >untracked && + >bar && git add foo* && - git stash push -- foo* && - test_path_is_missing "foo bar" && - test_path_is_missing foo && - test_path_is_file untracked && + 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 bar" && test_path_is_file foo && + test_path_is_file bar +' + +test_expect_success 'stash push -p with pathspec shows no changes only onece' ' + >file && + git add file && + git stash push -p not-file >actual && + echo "No local changes to save" >expect && + test_cmp expect actual +' + +test_expect_success 'stash push with pathspec shows no changes when there are none' ' + >file && + git add file && + git stash push not-file >actual && + echo "No local changes to save" >expect && + test_cmp expect actual +' + +test_expect_success 'untracked file is not removed when using pathspecs' ' + >untracked && + 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_expect_success 'stash without verb with pathspec' ' + >"foo bar" && + >foo && + >bar && + git add foo* && + git stash -- "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
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 9a98e31a3e..193adc7b68 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh@@ -197,16 +197,16 @@ test_expect_success 'stash push --include-untracked with pathspec' ' ' test_expect_success 'stash push with $IFS character' ' - >"foo bar" && + >"foo bar" && >foo && >bar && git add foo* && - git stash push --include-untracked -- foo* && - test_path_is_missing "foo bar" && - test_path_is_missing 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 bar" && test_path_is_file foo && test_path_is_file bar '
Thomas Gummerer (7): Documentation/stash: remove mention of git reset --hard stash: introduce push verb stash: add test for the create command line arguments stash: introduce new format create stash: teach 'push' (and 'create') to honor pathspec stash: use stash_push for no verb form stash: allow pathspecs in the no verb form Documentation/git-stash.txt | 21 ++++- git-stash.sh | 157 +++++++++++++++++++++++++++++++------ t/t3903-stash.sh | 127 +++++++++++++++++++++++++++++- t/t3905-stash-include-untracked.sh | 26 ++++++ 4 files changed, 302 insertions(+), 29 deletions(-) -- 2.11.0.301.g86e6ecc671.dirty