aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/stash.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/stash.c')
-rw-r--r--builtin/stash.c223
1 files changed, 136 insertions, 87 deletions
diff --git a/builtin/stash.c b/builtin/stash.c
index 2274aae255..b2813c614c 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,6 +1,12 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
#include "parse-options.h"
#include "refs.h"
#include "lockfile.h"
@@ -12,81 +18,108 @@
#include "run-command.h"
#include "dir.h"
#include "entry.h"
+#include "preload-index.h"
+#include "read-cache.h"
#include "rerere.h"
#include "revision.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "log-tree.h"
#include "diffcore.h"
-#include "exec-cmd.h"
#include "reflog.h"
+#include "add-interactive.h"
#define INCLUDE_ALL_FILES 2
+#define BUILTIN_STASH_LIST_USAGE \
+ N_("git stash list [<log-options>]")
+#define BUILTIN_STASH_SHOW_USAGE \
+ N_("git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]")
+#define BUILTIN_STASH_DROP_USAGE \
+ N_("git stash drop [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_POP_USAGE \
+ N_("git stash pop [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_APPLY_USAGE \
+ N_("git stash apply [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_BRANCH_USAGE \
+ N_("git stash branch <branchname> [<stash>]")
+#define BUILTIN_STASH_STORE_USAGE \
+ N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>")
+#define BUILTIN_STASH_PUSH_USAGE \
+ 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>...]]")
+#define BUILTIN_STASH_SAVE_USAGE \
+ N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+ " [-u | --include-untracked] [-a | --all] [<message>]")
+#define BUILTIN_STASH_CREATE_USAGE \
+ N_("git stash create [<message>]")
+#define BUILTIN_STASH_CLEAR_USAGE \
+ "git stash clear"
+
static const char * const git_stash_usage[] = {
- N_("git stash list [<options>]"),
- N_("git stash show [<options>] [<stash>]"),
- N_("git stash drop [-q|--quiet] [<stash>]"),
- N_("git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
- N_("git stash branch <branchname> [<stash>]"),
- "git stash clear",
- 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] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_LIST_USAGE,
+ BUILTIN_STASH_SHOW_USAGE,
+ BUILTIN_STASH_DROP_USAGE,
+ BUILTIN_STASH_POP_USAGE,
+ BUILTIN_STASH_APPLY_USAGE,
+ BUILTIN_STASH_BRANCH_USAGE,
+ BUILTIN_STASH_PUSH_USAGE,
+ BUILTIN_STASH_SAVE_USAGE,
+ BUILTIN_STASH_CLEAR_USAGE,
+ BUILTIN_STASH_CREATE_USAGE,
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_list_usage[] = {
- N_("git stash list [<options>]"),
+ BUILTIN_STASH_LIST_USAGE,
NULL
};
static const char * const git_stash_show_usage[] = {
- N_("git stash show [<options>] [<stash>]"),
+ BUILTIN_STASH_SHOW_USAGE,
NULL
};
static const char * const git_stash_drop_usage[] = {
- N_("git stash drop [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_DROP_USAGE,
NULL
};
static const char * const git_stash_pop_usage[] = {
- N_("git stash pop [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_POP_USAGE,
NULL
};
static const char * const git_stash_apply_usage[] = {
- N_("git stash apply [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_APPLY_USAGE,
NULL
};
static const char * const git_stash_branch_usage[] = {
- N_("git stash branch <branchname> [<stash>]"),
+ BUILTIN_STASH_BRANCH_USAGE,
NULL
};
static const char * const git_stash_clear_usage[] = {
- "git stash clear",
+ BUILTIN_STASH_CLEAR_USAGE,
NULL
};
static const char * const git_stash_store_usage[] = {
- N_("git stash store [-m|--message <message>] [-q|--quiet] <commit>"),
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_push_usage[] = {
- N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
- " [--] [<pathspec>...]]"),
+ BUILTIN_STASH_PUSH_USAGE,
NULL
};
static const char * const git_stash_save_usage[] = {
- N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_SAVE_USAGE,
NULL
};
@@ -177,7 +210,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
revision = info->revision.buf;
- if (get_oid(revision, &info->w_commit))
+ if (repo_get_oid(the_repository, revision, &info->w_commit))
return error(_("%s is not a valid reference"), revision);
assert_stash_like(info, revision);
@@ -187,7 +220,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
end_of_rev = strchrnul(revision, '@');
strbuf_add(&symbolic, revision, end_of_rev - revision);
- ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
+ ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len,
+ &dummy, &expanded_ref, 0);
strbuf_release(&symbolic);
switch (ret) {
case 0: /* Not found, but valid ref */
@@ -207,7 +241,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
static int do_clear_stash(void)
{
struct object_id obj;
- if (get_oid(ref_stash, &obj))
+ if (repo_get_oid(the_repository, ref_stash, &obj))
return 0;
return delete_ref(NULL, ref_stash, &obj, 0);
@@ -238,11 +272,11 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
struct tree *tree;
struct lock_file lock_file = LOCK_INIT;
- read_cache_preload(NULL);
- if (refresh_cache(REFRESH_QUIET))
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL))
return -1;
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
@@ -327,7 +361,7 @@ static int is_path_a_directory(const char *path)
}
static void add_diff_to_buf(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -403,7 +437,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* to the index before a merge was run) and the current index
* (reflecting the changes brought in by the merge).
*/
- diff_setup(&diff_opts);
+ repo_diff_setup(the_repository, &diff_opts);
diff_opts.flags.recursive = 1;
diff_opts.detect_rename = 0;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -431,10 +465,10 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
* path, but left it out of the working tree, then clear the
* SKIP_WORKTREE bit and write it to the working tree.
*/
- if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+ if (pos >= 0 && ce_skip_worktree(the_index.cache[pos])) {
struct stat st;
- ce = active_cache[pos];
+ ce = the_index.cache[pos];
if (!lstat(ce->name, &st)) {
/* Conflicting path present; relocate it */
struct strbuf new_path = STRBUF_INIT;
@@ -500,11 +534,13 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
struct tree *head, *merge, *merge_base;
struct lock_file lock = LOCK_INIT;
- read_cache_preload(NULL);
- if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL))
return -1;
- if (write_cache_as_tree(&c_tree, 0, NULL))
+ if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
+ NULL))
return error(_("cannot apply a stash in the middle of a merge"));
if (index) {
@@ -526,14 +562,15 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
return error(_("conflicts in index. "
"Try without --index."));
- discard_cache();
- read_cache();
- if (write_cache_as_tree(&index_tree, 0, NULL))
+ discard_index(&the_index);
+ repo_read_index(the_repository);
+ if (write_index_as_tree(&index_tree, &the_index,
+ get_index_file(), 0, NULL))
return error(_("could not save index tree"));
reset_head();
- discard_cache();
- read_cache();
+ discard_index(&the_index);
+ repo_read_index(the_repository);
}
}
@@ -573,7 +610,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
ret = error(_("could not write index"));
if (ret) {
- rerere(0);
+ repo_rerere(the_repository, 0);
if (index)
fprintf_ln(stderr, _("Index was not unstashed."));
@@ -803,7 +840,8 @@ static int show_stat = 1;
static int show_patch;
static int show_include_untracked;
-static int git_stash_config(const char *var, const char *value, void *cb)
+static int git_stash_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "stash.showstat")) {
show_stat = git_config_bool(var, value);
@@ -817,7 +855,7 @@ static int git_stash_config(const char *var, const char *value, void *cb)
show_include_untracked = git_config_bool(var, value);
return 0;
}
- return git_diff_basic_config(var, value, cb);
+ return git_diff_basic_config(var, value, ctx, cb);
}
static void diff_include_untracked(const struct stash_info *info, struct diff_options *diff_opt)
@@ -873,7 +911,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL);
- init_revisions(&rev, prefix);
+ repo_init_revisions(the_repository, &rev, prefix);
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -934,7 +972,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
}
log_tree_diff_flush(&rev);
- ret = diff_result_code(&rev.diffopt, 0);
+ ret = diff_result_code(&rev.diffopt);
cleanup:
strvec_clear(&stash_args);
free_stash_info(&info);
@@ -950,6 +988,12 @@ usage:
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
int quiet)
{
+ struct stash_info info;
+ char revision[GIT_MAX_HEXSZ];
+
+ oid_to_hex_r(revision, w_commit);
+ assert_stash_like(&info, revision);
+
if (!stash_msg)
stash_msg = "Created via \"git stash store\".";
@@ -1050,19 +1094,18 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
*/
static int check_changes_tracked_files(const struct pathspec *ps)
{
- int result;
struct rev_info rev;
struct object_id dummy;
int ret = 0;
/* No initial commit. */
- if (get_oid("HEAD", &dummy))
+ if (repo_get_oid(the_repository, "HEAD", &dummy))
return -1;
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
return -1;
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
rev.diffopt.flags.quick = 1;
@@ -1072,14 +1115,14 @@ static int check_changes_tracked_files(const struct pathspec *ps)
add_head_to_pending(&rev);
diff_setup_done(&rev.diffopt);
- result = run_diff_index(&rev, 1);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_index(&rev, DIFF_INDEX_CACHED);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
- result = run_diff_files(&rev, 0);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_files(&rev, 0);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
@@ -1113,7 +1156,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
int ret = 0;
struct strbuf untracked_msg = STRBUF_INIT;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
@@ -1141,7 +1184,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
}
done:
- discard_index(&istate);
+ release_index(&istate);
strbuf_release(&untracked_msg);
remove_path(stash_index_path.buf);
return ret;
@@ -1152,7 +1195,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
{
int ret = 0;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
0, NULL)) {
@@ -1175,7 +1218,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
}
done:
- discard_index(&istate);
+ release_index(&istate);
return ret;
}
@@ -1185,7 +1228,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf);
@@ -1205,7 +1248,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- ret = run_add_interactive(NULL, "--patch=stash", ps);
+ ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
@@ -1236,7 +1279,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
}
done:
- discard_index(&istate);
+ release_index(&istate);
remove_path(stash_index_path.buf);
return ret;
}
@@ -1247,9 +1290,9 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
struct rev_info rev;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
struct strbuf diff_output = STRBUF_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
- init_revisions(&rev, NULL);
+ repo_init_revisions(the_repository, &rev, NULL);
copy_pathspec(&rev.prune_data, ps);
set_alternate_index_output(stash_index_path.buf);
@@ -1263,17 +1306,14 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
rev.diffopt.format_callback = add_diff_to_buf;
rev.diffopt.format_callback_data = &diff_output;
- if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
ret = -1;
goto done;
}
add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
"");
- if (run_diff_index(&rev, 0)) {
- ret = -1;
- goto done;
- }
+ run_diff_index(&rev, 0);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index",
@@ -1295,7 +1335,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
}
done:
- discard_index(&istate);
+ release_index(&istate);
release_revisions(&rev);
strbuf_release(&diff_output);
remove_path(stash_index_path.buf);
@@ -1321,13 +1361,14 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
prepare_fallback_ident("git stash", "git@stash");
- read_cache_preload(NULL);
- if (refresh_and_write_cache(REFRESH_QUIET, 0, 0) < 0) {
+ repo_read_index_preload(the_repository, NULL, 0);
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL) < 0) {
ret = -1;
goto done;
}
- if (get_oid("HEAD", &info->b_commit)) {
+ if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) {
if (!quiet)
fprintf_ln(stderr, _("You do not have "
"the initial commit yet"));
@@ -1345,14 +1386,16 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
skip_prefix(branch_ref, "refs/heads/", &branch_name);
- head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
- DEFAULT_ABBREV);
+ head_short_sha1 = repo_find_unique_abbrev(the_repository,
+ &head_commit->object.oid,
+ DEFAULT_ABBREV);
strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
commit_list_insert(head_commit, &parents);
- if (write_cache_as_tree(&info->i_tree, 0, NULL) ||
+ if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
+ NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
if (!quiet)
@@ -1436,7 +1479,7 @@ done:
return ret;
}
-static int create_stash(int argc, const char **argv, const char *prefix)
+static int create_stash(int argc, const char **argv, const char *prefix UNUSED)
{
int ret;
struct strbuf stash_msg_buf = STRBUF_INIT;
@@ -1490,15 +1533,15 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
- read_cache_preload(NULL);
+ repo_read_index_preload(the_repository, NULL, 0);
if (!include_untracked && ps->nr) {
int i;
char *ps_matched = xcalloc(ps->nr, 1);
/* TODO: audit for interaction with sparse-index. */
ensure_full_index(&the_index);
- for (i = 0; i < active_nr; i++)
- ce_path_match(&the_index, active_cache[i], ps,
+ for (i = 0; i < the_index.cache_nr; i++)
+ ce_path_match(&the_index, the_index.cache[i], ps,
ps_matched);
if (report_path_error(ps_matched, ps)) {
@@ -1510,7 +1553,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
free(ps_matched);
}
- if (refresh_and_write_cache(REFRESH_QUIET, 0, 0)) {
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+ NULL, NULL, NULL)) {
ret = -1;
goto done;
}
@@ -1567,7 +1611,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
goto done;
}
}
- discard_cache();
+ discard_index(&the_index);
if (ps->nr) {
struct child_process cp_add = CHILD_PROCESS_INIT;
struct child_process cp_diff = CHILD_PROCESS_INIT;
@@ -1663,8 +1707,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
done:
+ strbuf_release(&patch);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
+ strbuf_release(&untracked_files);
return ret;
}
@@ -1699,6 +1745,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END()
};
+ int ret;
if (argc) {
force_assume = !strcmp(argv[0], "-p");
@@ -1738,8 +1785,10 @@ static int push_stash(int argc, const char **argv, const char *prefix,
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, only_staged);
+ ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
+ include_untracked, only_staged);
+ clear_pathspec(&ps);
+ return ret;
}
static int push_stash_unassumed(int argc, const char **argv, const char *prefix)