stash: implement '--staged' option for 'push' and 'save'

Stash only the changes that are staged.

This mode allows to easily stash-out for later reuse some changes
unrelated to the current work in progress.

Unlike 'stash push --patch', --staged supports use of any tool to
select the changes to stash-out, including, but not limited to 'git
add --interactive'.

Signed-off-by: Sergey Organov <sorganov@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Sergey Organov
2021-10-18 19:09:06 +03:00
committed by Junio C Hamano
parent f443b226ca
commit 41a28eb6c1
3 changed files with 113 additions and 12 deletions

View File

@ -27,11 +27,11 @@ static const char * const git_stash_usage[] = {
N_("git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
N_("git stash branch <branchname> [<stash>]"),
"git stash clear",
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
N_("git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
" [--] [<pathspec>...]]"),
N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
N_("git stash save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [<message>]"),
NULL
};
@ -1132,6 +1132,38 @@ done:
return ret;
}
static int stash_staged(struct stash_info *info, const struct pathspec *ps,
struct strbuf *out_patch, int quiet)
{
int ret = 0;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
struct index_state istate = { NULL };
if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
0, NULL)) {
ret = -1;
goto done;
}
cp_diff_tree.git_cmd = 1;
strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
oid_to_hex(&info->w_tree), "--", NULL);
if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
ret = -1;
goto done;
}
if (!out_patch->len) {
if (!quiet)
fprintf_ln(stderr, _("No staged changes"));
ret = 1;
}
done:
discard_index(&istate);
return ret;
}
static int stash_patch(struct stash_info *info, const struct pathspec *ps,
struct strbuf *out_patch, int quiet)
{
@ -1258,7 +1290,7 @@ done:
}
static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf,
int include_untracked, int patch_mode,
int include_untracked, int patch_mode, int only_staged,
struct stash_info *info, struct strbuf *patch,
int quiet)
{
@ -1337,6 +1369,16 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
} else if (ret > 0) {
goto done;
}
} else if (only_staged) {
ret = stash_staged(info, ps, patch, quiet);
if (ret < 0) {
if (!quiet)
fprintf_ln(stderr, _("Cannot save the current "
"staged state"));
goto done;
} else if (ret > 0) {
goto done;
}
} else {
if (stash_working_tree(info, ps)) {
if (!quiet)
@ -1395,7 +1437,7 @@ static int create_stash(int argc, const char **argv, const char *prefix)
if (!check_changes_tracked_files(&ps))
return 0;
ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, &info,
ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info,
NULL, 0);
if (!ret)
printf_ln("%s", oid_to_hex(&info.w_commit));
@ -1405,7 +1447,7 @@ static int create_stash(int argc, const char **argv, const char *prefix)
}
static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet,
int keep_index, int patch_mode, int include_untracked)
int keep_index, int patch_mode, int include_untracked, int only_staged)
{
int ret = 0;
struct stash_info info;
@ -1423,6 +1465,17 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
/* --patch overrides --staged */
if (patch_mode)
only_staged = 0;
if (only_staged && include_untracked) {
fprintf_ln(stderr, _("Can't use --staged and --include-untracked"
" or --all at the same time"));
ret = -1;
goto done;
}
read_cache_preload(NULL);
if (!include_untracked && ps->nr) {
int i;
@ -1463,7 +1516,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
if (stash_msg)
strbuf_addstr(&stash_msg_buf, stash_msg);
if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode,
if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged,
&info, &patch, quiet)) {
ret = -1;
goto done;
@ -1480,7 +1533,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
printf_ln(_("Saved working directory and index state %s"),
stash_msg_buf.buf);
if (!patch_mode) {
if (!(patch_mode || only_staged)) {
if (include_untracked && !ps->nr) {
struct child_process cp = CHILD_PROCESS_INIT;
@ -1598,6 +1651,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
{
int force_assume = 0;
int keep_index = -1;
int only_staged = 0;
int patch_mode = 0;
int include_untracked = 0;
int quiet = 0;
@ -1608,6 +1662,8 @@ static int push_stash(int argc, const char **argv, const char *prefix,
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
OPT_BOOL('S', "staged", &only_staged,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
OPT__QUIET(&quiet, N_("quiet mode")),
@ -1646,6 +1702,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,
if (patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
if (only_staged)
die(_("--pathspec-from-file is incompatible with --staged"));
if (ps.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
@ -1657,12 +1716,13 @@ static int push_stash(int argc, const char **argv, const char *prefix,
}
return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
include_untracked);
include_untracked, only_staged);
}
static int save_stash(int argc, const char **argv, const char *prefix)
{
int keep_index = -1;
int only_staged = 0;
int patch_mode = 0;
int include_untracked = 0;
int quiet = 0;
@ -1673,6 +1733,8 @@ static int save_stash(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
OPT_BOOL('S', "staged", &only_staged,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
OPT__QUIET(&quiet, N_("quiet mode")),
@ -1694,7 +1756,7 @@ static int save_stash(int argc, const char **argv, const char *prefix)
memset(&ps, 0, sizeof(ps));
ret = do_push_stash(&ps, stash_msg, quiet, keep_index,
patch_mode, include_untracked);
patch_mode, include_untracked, only_staged);
strbuf_release(&stash_msg_buf);
return ret;