summaryrefslogtreecommitdiff
path: root/builtin/stash.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/stash.c')
-rw-r--r--builtin/stash.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/builtin/stash.c b/builtin/stash.c
index 46b981c4dd..fcfd97972a 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -574,7 +574,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
}
}
- init_merge_options(&o, the_repository);
+ init_ui_merge_options(&o, the_repository);
o.branch1 = "Updated upstream";
o.branch2 = "Stashed changes";
@@ -1521,6 +1521,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
struct strbuf patch = STRBUF_INIT;
struct strbuf stash_msg_buf = STRBUF_INIT;
struct strbuf untracked_files = STRBUF_INIT;
+ struct strbuf out = STRBUF_INIT;
if (patch_mode && keep_index == -1)
keep_index = 1;
@@ -1626,7 +1627,6 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
struct child_process cp_add = CHILD_PROCESS_INIT;
struct child_process cp_diff = CHILD_PROCESS_INIT;
struct child_process cp_apply = CHILD_PROCESS_INIT;
- struct strbuf out = STRBUF_INIT;
cp_add.git_cmd = 1;
strvec_push(&cp_add.args, "add");
@@ -1671,7 +1671,28 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
}
- if (keep_index == 1 && !is_null_oid(&info.i_tree)) {
+ /*
+ * When keeping staged entries, we need to reset the working
+ * directory to match the state of our index. This can be
+ * skipped when the index is the empty tree, because there is
+ * nothing to reset in that case:
+ *
+ * - When the index has any file, regardless of whether
+ * staged or not, the tree cannot be empty by definition
+ * and thus we enter the condition.
+ *
+ * - When the index has no files, the only thing we need to
+ * care about is untracked files when `--include-untracked`
+ * is given. But as we already execute git-clean(1) further
+ * up to delete such untracked files we don't have to do
+ * anything here, either.
+ *
+ * We thus skip calling git-checkout(1) in this case, also
+ * because running it on an empty tree will cause it to fail
+ * due to the pathspec not matching anything.
+ */
+ if (keep_index == 1 && !is_null_oid(&info.i_tree) &&
+ !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;
@@ -1718,6 +1739,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
done:
strbuf_release(&patch);
+ strbuf_release(&out);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
strbuf_release(&untracked_files);
@@ -1869,6 +1891,8 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
OPT_END()
};
+ const char **args_copy;
+ int ret;
git_config(git_stash_config, NULL);
@@ -1892,5 +1916,16 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
/* Assume 'stash push' */
strvec_push(&args, "push");
strvec_pushv(&args, argv);
- return !!push_stash(args.nr, args.v, prefix, 1);
+
+ /*
+ * `push_stash()` ends up modifying the array, which causes memory
+ * leaks if we didn't copy the array here.
+ */
+ DUP_ARRAY(args_copy, args.v, args.nr);
+
+ ret = !!push_stash(args.nr, args_copy, prefix, 1);
+
+ strvec_clear(&args);
+ free(args_copy);
+ return ret;
}