config.mak.uname: set FREAD_READS_DIRECTORIES for Linux and FreeBSD
[gitweb.git] / git-stash.sh
index ef5d1b45be932e49b566d0d2df55557a5b737c3e..2fb651b2b8d9d91a130b1cbd11c3c2b6b1cf961b 100755 (executable)
@@ -7,10 +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 push [--patch] [-k|--[no-]keep-index] [-q|--quiet]
-                     [-u|--include-untracked] [-a|--all] [-m <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
@@ -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,32 +278,45 @@ 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 -q -- "$@"
+                       git ls-files -z --modified -- "$@" |
+                       git checkout-index -z --force --stdin
+                       git clean --force -q -d -- "$@"
+               else
+                       git reset --hard -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"
                then
-                       git read-tree --reset -u $i_tree
+                       git read-tree --reset $i_tree
+                       git ls-files -z --modified -- "$@" |
+                       git checkout-index -z --force --stdin
                fi
        else
                git apply -R < "$TMP-patch" ||
@@ -306,7 +324,7 @@ push_stash () {
 
                if test "$keep_index" != "t"
                then
-                       git reset
+                       git reset -q -- "$@"
                fi
        fi
 }
@@ -640,18 +658,21 @@ apply_to_branch () {
        }
 }
 
+test "$1" = "-p" && set "push" "$@"
+
 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
@@ -702,7 +723,7 @@ branch)
 *)
        case $# in
        0)
-               save_stash &&
+               push_stash &&
                say "$(gettext "(To restore them type \"git stash apply\")")"
                ;;
        *)