summaryrefslogtreecommitdiff
path: root/builtin/stash.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/stash.c')
-rw-r--r--builtin/stash.c100
1 files changed, 83 insertions, 17 deletions
diff --git a/builtin/stash.c b/builtin/stash.c
index a0ccc8654d..1ef2017c59 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -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
};
@@ -561,18 +561,19 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (index)
fprintf_ln(stderr, _("Index was not unstashed."));
- return ret;
+ goto restore_untracked;
}
if (has_index) {
if (reset_tree(&index_tree, 0, 0))
- return -1;
+ ret = -1;
} else {
unstage_changes_unless_new(&c_tree);
}
+restore_untracked:
if (info->has_u && restore_untracked(&info->u_tree))
- return error(_("could not restore untracked files from stash"));
+ ret = error(_("could not restore untracked files from stash"));
if (!quiet) {
struct child_process cp = CHILD_PROCESS_INIT;
@@ -592,7 +593,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
run_command(&cp);
}
- return 0;
+ return ret;
}
static int apply_stash(int argc, const char **argv, const char *prefix)
@@ -1132,6 +1133,38 @@ done:
return ret;
}
+static int stash_staged(struct stash_info *info, 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 +1291,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 +1370,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, 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 +1438,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 +1448,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 +1466,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 +1517,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,13 +1534,15 @@ 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;
cp.git_cmd = 1;
+ if (startup_info->original_cwd)
+ cp.dir = startup_info->original_cwd;
strvec_pushl(&cp.args, "clean", "--force",
- "--quiet", "-d", NULL);
+ "--quiet", "-d", ":/", NULL);
if (include_untracked == INCLUDE_ALL_FILES)
strvec_push(&cp.args, "-x");
if (run_command(&cp)) {
@@ -1598,6 +1654,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 +1665,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")),
@@ -1625,6 +1684,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
if (argc) {
force_assume = !strcmp(argv[0], "-p");
argc = parse_options(argc, argv, prefix, options,
+ push_assumed ? git_stash_usage :
git_stash_push_usage,
PARSE_OPT_KEEP_DASHDASH);
}
@@ -1644,25 +1704,29 @@ static int push_stash(int argc, const char **argv, const char *prefix,
if (pathspec_from_file) {
if (patch_mode)
- die(_("--pathspec-from-file is incompatible with --patch"));
+ die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--patch");
+
+ if (only_staged)
+ die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--staged");
if (ps.nr)
- die(_("--pathspec-from-file is incompatible with pathspec arguments"));
+ die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
parse_pathspec_file(&ps, 0,
PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
- die(_("--pathspec-file-nul requires --pathspec-from-file"));
+ die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
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 +1737,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 +1760,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;