Hi Paul,

On Fri, 31 Aug 2018, Paul-Sebastian Ungureanu wrote:

> Add stash save to the helper and delete functions which are no
> longer needed (`show_help()`, `save_stash()`, `push_stash()`,
> `create_stash()`, `clear_stash()`, `untracked_files()` and
> `no_changes()`).
> 
> The `-m` option is no longer supported as it might not make
> sense to have two ways of passing a message. Even if this is
> a change in behaviour, the documentation remains the same
> because the `-m` parameter was omitted before.

It makes me slightly nervous to remove the `-m` option like this. And I
wonder how difficult it would be to allow for the `-m` option, still, just
to keep the occasional script running that might rely on this feature.

I could imagine that it would be as easy as

        const char *stash_msg = NULL;
        [...]
                OPT_STRING('m', "message", &stash_msg, "message",
                           N_("stash message")),
        [...]
        struct strbuf buf = STRBUF_INIT;

        [... parse_options() ...]
        if (argc)
                stash_msg = strbuf_join_argv(&buf, argc, argv, ' ');

        [...]

        strbuf_release(&buf);

where `strbuf_join_argv()` would be implemented like this (and I would put
it into strbuf.c and strbuf.h:

        const char *strbuf_join_argv(struct strbuf *buf,
                                     int argc, const char **argv, char delim)
        {
                if (!argc)
                        return buf->buf;

                strbuf_addstr(buf, *argv);
                while (--i) {
                        strbuf_addch(buf, delim);
                        strbuf_addstr(buf, *(++argv);
                }

                return buf->buf;
        }

> diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
> index e5153a63ea..1269f2548c 100644
> --- a/builtin/stash--helper.c
> +++ b/builtin/stash--helper.c
> @@ -1444,6 +1452,48 @@ static int push_stash(int argc, const char **argv, 
> const char *prefix)
>                            include_untracked);
>  }
>  
> +static int save_stash(int argc, const char **argv, const char *prefix)
> +{
> +     int i;
> +     int keep_index = -1;
> +     int patch_mode = 0;
> +     int include_untracked = 0;
> +     int quiet = 0;
> +     int ret = 0;
> +     const char *stash_msg = NULL;
> +     char *to_free = NULL;
> +     struct strbuf stash_msg_buf = STRBUF_INIT;
> +     struct pathspec ps;
> +     struct option options[] = {
> +             OPT_SET_INT('k', "keep-index", &keep_index,
> +                     N_("keep index"), 1),
> +             OPT_BOOL('p', "patch", &patch_mode,
> +                     N_("stash in patch mode")),
> +             OPT__QUIET(&quiet, N_("quiet mode")),
> +             OPT_BOOL('u', "include-untracked", &include_untracked,
> +                      N_("include untracked files in stash")),
> +             OPT_SET_INT('a', "all", &include_untracked,
> +                         N_("include ignore files"), 2),
> +             OPT_END()
> +     };
> +
> +     argc = parse_options(argc, argv, prefix, options,
> +                          git_stash_helper_save_usage,
> +                          0);
> +
> +     for (i = 0; i < argc; ++i)
> +             strbuf_addf(&stash_msg_buf, "%s ", argv[i]);

I think I saw this in another patch already, and now it makes sense to
introduce the `strbuf_join_argv()` function, methinks.

> +     stash_msg = strbuf_detach(&stash_msg_buf, NULL);
> +     to_free = (char *) stash_msg;
> +
> +     memset(&ps, 0, sizeof(ps));
> +     ret = do_push_stash(ps, stash_msg, quiet, keep_index, patch_mode,
> +                         include_untracked);
> +
> +     free(to_free);

As before, I would recommend to use stash_msg_buf.buf directly and call
strbuf_release() in the end (and drop the `to_free` variable altogether).

The rest looks good to me!

Thanks,
Dscho

> +     return ret;
> +}
> +
>  int cmd_stash__helper(int argc, const char **argv, const char *prefix)
>  {
>       pid_t pid = getpid();
> @@ -1484,6 +1534,8 @@ int cmd_stash__helper(int argc, const char **argv, 
> const char *prefix)
>               return !!create_stash(argc, argv, prefix);
>       else if (!strcmp(argv[0], "push"))
>               return !!push_stash(argc, argv, prefix);
> +     else if (!strcmp(argv[0], "save"))
> +             return !!save_stash(argc, argv, prefix);
>  
>       usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
>                     git_stash_helper_usage, options);
> diff --git a/git-stash.sh b/git-stash.sh
> index c3146f62ab..695f1feba3 100755
> --- a/git-stash.sh
> +++ b/git-stash.sh
> @@ -36,314 +36,6 @@ else
>         reset_color=
>  fi
>  
> -no_changes () {
> -     git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
> -     git diff-files --quiet --ignore-submodules -- "$@" &&
> -     (test -z "$untracked" || test -z "$(untracked_files "$@")")
> -}
> -
> -untracked_files () {
> -     if test "$1" = "-z"
> -     then
> -             shift
> -             z=-z
> -     else
> -             z=
> -     fi
> -     excl_opt=--exclude-standard
> -     test "$untracked" = "all" && excl_opt=
> -     git ls-files -o $z $excl_opt -- "$@"
> -}
> -
> -clear_stash () {
> -     if test $# != 0
> -     then
> -             die "$(gettext "git stash clear with parameters is 
> unimplemented")"
> -     fi
> -     if current=$(git rev-parse --verify --quiet $ref_stash)
> -     then
> -             git update-ref -d $ref_stash $current
> -     fi
> -}
> -
> -create_stash () {
> -     stash_msg=
> -     untracked=
> -     while test $# != 0
> -     do
> -             case "$1" in
> -             -m|--message)
> -                     shift
> -                     stash_msg=${1?"BUG: create_stash () -m requires an 
> argument"}
> -                     ;;
> -             -m*)
> -                     stash_msg=${1#-m}
> -                     ;;
> -             --message=*)
> -                     stash_msg=${1#--message=}
> -                     ;;
> -             -u|--include-untracked)
> -                     shift
> -                     untracked=${1?"BUG: create_stash () -u requires an 
> argument"}
> -                     ;;
> -             --)
> -                     shift
> -                     break
> -                     ;;
> -             esac
> -             shift
> -     done
> -
> -     git update-index -q --refresh
> -     if no_changes "$@"
> -     then
> -             exit 0
> -     fi
> -
> -     # state of the base commit
> -     if b_commit=$(git rev-parse --verify HEAD)
> -     then
> -             head=$(git rev-list --oneline -n 1 HEAD --)
> -     else
> -             die "$(gettext "You do not have the initial commit yet")"
> -     fi
> -
> -     if branch=$(git symbolic-ref -q HEAD)
> -     then
> -             branch=${branch#refs/heads/}
> -     else
> -             branch='(no branch)'
> -     fi
> -     msg=$(printf '%s: %s' "$branch" "$head")
> -
> -     # state of the index
> -     i_tree=$(git write-tree) &&
> -     i_commit=$(printf 'index on %s\n' "$msg" |
> -             git commit-tree $i_tree -p $b_commit) ||
> -             die "$(gettext "Cannot save the current index state")"
> -
> -     if test -n "$untracked"
> -     then
> -             # Untracked files are stored by themselves in a parentless 
> commit, for
> -             # ease of unpacking later.
> -             u_commit=$(
> -                     untracked_files -z "$@" | (
> -                             GIT_INDEX_FILE="$TMPindex" &&
> -                             export GIT_INDEX_FILE &&
> -                             rm -f "$TMPindex" &&
> -                             git update-index -z --add --remove --stdin &&
> -                             u_tree=$(git write-tree) &&
> -                             printf 'untracked files on %s\n' "$msg" | git 
> commit-tree $u_tree  &&
> -                             rm -f "$TMPindex"
> -             ) ) || die "$(gettext "Cannot save the untracked files")"
> -
> -             untracked_commit_option="-p $u_commit";
> -     else
> -             untracked_commit_option=
> -     fi
> -
> -     if test -z "$patch_mode"
> -     then
> -
> -             # state of the working tree
> -             w_tree=$( (
> -                     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 update-index -z --add --remove --stdin 
> <"$TMP-stagenames" &&
> -                     git write-tree &&
> -                     rm -f "$TMPindex"
> -             ) ) ||
> -                     die "$(gettext "Cannot save the current worktree 
> state")"
> -
> -     else
> -
> -             rm -f "$TMP-index" &&
> -             GIT_INDEX_FILE="$TMP-index" git read-tree HEAD &&
> -
> -             # find out what the user wants
> -             GIT_INDEX_FILE="$TMP-index" \
> -                     git add--interactive --patch=stash -- "$@" &&
> -
> -             # state of the working tree
> -             w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
> -             die "$(gettext "Cannot save the current worktree state")"
> -
> -             git diff-tree -p HEAD $w_tree -- >"$TMP-patch" &&
> -             test -s "$TMP-patch" ||
> -             die "$(gettext "No changes selected")"
> -
> -             rm -f "$TMP-index" ||
> -             die "$(gettext "Cannot remove temporary index (can't happen)")"
> -
> -     fi
> -
> -     # create the stash
> -     if test -z "$stash_msg"
> -     then
> -             stash_msg=$(printf 'WIP on %s' "$msg")
> -     else
> -             stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
> -     fi
> -     w_commit=$(printf '%s\n' "$stash_msg" |
> -     git commit-tree $w_tree -p $b_commit -p $i_commit 
> $untracked_commit_option) ||
> -     die "$(gettext "Cannot record working tree state")"
> -}
> -
> -push_stash () {
> -     keep_index=
> -     patch_mode=
> -     untracked=
> -     stash_msg=
> -     while test $# != 0
> -     do
> -             case "$1" in
> -             -k|--keep-index)
> -                     keep_index=t
> -                     ;;
> -             --no-keep-index)
> -                     keep_index=n
> -                     ;;
> -             -p|--patch)
> -                     patch_mode=t
> -                     # only default to keep if we don't already have an 
> override
> -                     test -z "$keep_index" && keep_index=t
> -                     ;;
> -             -q|--quiet)
> -                     GIT_QUIET=t
> -                     ;;
> -             -u|--include-untracked)
> -                     untracked=untracked
> -                     ;;
> -             -a|--all)
> -                     untracked=all
> -                     ;;
> -             -m|--message)
> -                     shift
> -                     test -z ${1+x} && usage
> -                     stash_msg=$1
> -                     ;;
> -             -m*)
> -                     stash_msg=${1#-m}
> -                     ;;
> -             --message=*)
> -                     stash_msg=${1#--message=}
> -                     ;;
> -             --help)
> -                     show_help
> -                     ;;
> -             --)
> -                     shift
> -                     break
> -                     ;;
> -             -*)
> -                     option="$1"
> -                     eval_gettextln "error: unknown option for 'stash push': 
> \$option"
> -                     usage
> -                     ;;
> -             *)
> -                     break
> -                     ;;
> -             esac
> -             shift
> -     done
> -
> -     eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
> -
> -     if test -n "$patch_mode" && test -n "$untracked"
> -     then
> -             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 "$@"
> -     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" -- "$@"
> -     git stash--helper store -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
> -             test "$untracked" = "all" && CLEAN_X_OPTION=-x || 
> CLEAN_X_OPTION=
> -             if test -n "$untracked" && test $# = 0
> -             then
> -                     git clean --force --quiet -d $CLEAN_X_OPTION
> -             fi
> -
> -             if test $# != 0
> -             then
> -                     test -z "$untracked" && UPDATE_OPTION="-u" || 
> UPDATE_OPTION=
> -                     test "$untracked" = "all" && FORCE_OPTION="--force" || 
> FORCE_OPTION=
> -                     git add $UPDATE_OPTION $FORCE_OPTION -- "$@"
> -                     git diff-index -p --cached --binary HEAD -- "$@" |
> -                     git apply --index -R
> -             else
> -                     git reset --hard -q
> -             fi
> -
> -             if test "$keep_index" = "t" && test -n "$i_tree"
> -             then
> -                     git read-tree --reset $i_tree
> -                     git ls-files -z --modified -- "$@" |
> -                     git checkout-index -z --force --stdin
> -             fi
> -     else
> -             git apply -R < "$TMP-patch" ||
> -             die "$(gettext "Cannot remove worktree changes")"
> -
> -             if test "$keep_index" != "t"
> -             then
> -                     git reset -q -- "$@"
> -             fi
> -     fi
> -}
> -
> -save_stash () {
> -     push_options=
> -     while test $# != 0
> -     do
> -             case "$1" in
> -             --)
> -                     shift
> -                     break
> -                     ;;
> -             -*)
> -                     # pass all options through to push_stash
> -                     push_options="$push_options $1"
> -                     ;;
> -             *)
> -                     break
> -                     ;;
> -             esac
> -             shift
> -     done
> -
> -     stash_msg="$*"
> -
> -     if test -z "$stash_msg"
> -     then
> -             push_stash $push_options
> -     else
> -             push_stash $push_options -m "$stash_msg"
> -     fi
> -}
> -
> -show_help () {
> -     exec git help stash
> -     exit 1
> -}
> -
>  #
>  # Parses the remaining options looking for flags and
>  # at most one revision defaulting to ${ref_stash}@{0}
> @@ -408,7 +100,8 @@ show)
>       ;;
>  save)
>       shift
> -     save_stash "$@"
> +     cd "$START_DIR"
> +     git stash--helper save "$@"
>       ;;
>  push)
>       shift
> -- 
> 2.19.0.rc0.22.gc26283d74e
> 
> 

Reply via email to