Browse Source

stash: convert save to builtin

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()`).

Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Paul-Sebastian Ungureanu 6 years ago committed by Junio C Hamano
parent
commit
64fe9c26a4
  1. 50
      builtin/stash--helper.c
  2. 328
      git-stash.sh

50
builtin/stash--helper.c

@ -26,6 +26,8 @@ static const char * const git_stash_helper_usage[] = { @@ -26,6 +26,8 @@ static const char * const git_stash_helper_usage[] = {
N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
" [--] [<pathspec>...]]"),
N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [<message>]"),
NULL
};

@ -81,6 +83,12 @@ static const char * const git_stash_helper_push_usage[] = { @@ -81,6 +83,12 @@ static const char * const git_stash_helper_push_usage[] = {
NULL
};

static const char * const git_stash_helper_save_usage[] = {
N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [<message>]"),
NULL
};

static const char *ref_stash = "refs/stash";
static struct strbuf stash_index_path = STRBUF_INIT;

@ -1486,6 +1494,46 @@ static int push_stash(int argc, const char **argv, const char *prefix) @@ -1486,6 +1494,46 @@ 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 keep_index = -1;
int patch_mode = 0;
int include_untracked = 0;
int quiet = 0;
int ret = 0;
const char *stash_msg = NULL;
struct pathspec ps;
struct strbuf stash_msg_buf = STRBUF_INIT;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
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_STRING('m', "message", &stash_msg, "message",
N_("stash message")),
OPT_END()
};

argc = parse_options(argc, argv, prefix, options,
git_stash_helper_save_usage,
PARSE_OPT_KEEP_DASHDASH);

if (argc)
stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');

memset(&ps, 0, sizeof(ps));
ret = do_push_stash(ps, stash_msg, quiet, keep_index,
patch_mode, include_untracked);

strbuf_release(&stash_msg_buf);
return ret;
}

int cmd_stash__helper(int argc, const char **argv, const char *prefix)
{
pid_t pid = getpid();
@ -1526,6 +1574,8 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix) @@ -1526,6 +1574,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);

328
git-stash.sh

@ -36,331 +36,6 @@ else @@ -36,331 +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 -- "$@"
}

prepare_fallback_ident () {
if ! git -c user.useconfigonly=yes var GIT_COMMITTER_IDENT >/dev/null 2>&1
then
GIT_AUTHOR_NAME="git stash"
GIT_AUTHOR_EMAIL=git@stash
GIT_COMMITTER_NAME="git stash"
GIT_COMMITTER_EMAIL=git@stash
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL
export GIT_COMMITTER_NAME
export GIT_COMMITTER_EMAIL
fi
}

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 () {

prepare_fallback_ident

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}
@ -425,7 +100,8 @@ show) @@ -425,7 +100,8 @@ show)
;;
save)
shift
save_stash "$@"
cd "$START_DIR"
git stash--helper save "$@"
;;
push)
shift

Loading…
Cancel
Save