summaryrefslogtreecommitdiff
path: root/builtin/reset.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/reset.c')
-rw-r--r--builtin/reset.c187
1 files changed, 129 insertions, 58 deletions
diff --git a/builtin/reset.c b/builtin/reset.c
index 8ae69d6..1d62ff6 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,24 +7,34 @@
*
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
-#include "tag.h"
#include "object.h"
#include "pretty.h"
-#include "run-command.h"
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
#include "tree.h"
#include "branch.h"
+#include "object-name.h"
#include "parse-options.h"
+#include "path.h"
#include "unpack-trees.h"
#include "cache-tree.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "submodule.h"
-#include "submodule-config.h"
+#include "trace.h"
+#include "trace2.h"
+#include "dir.h"
+#include "add-interactive.h"
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
@@ -67,19 +77,27 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
case KEEP:
case MERGE:
opts.update = 1;
+ opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
break;
case HARD:
opts.update = 1;
- /* fallthrough */
+ opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+ opts.skip_cache_tree_update = 1;
+ break;
+ case MIXED:
+ opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
+ opts.skip_cache_tree_update = 1;
+ /* but opts.update=0, so working tree not updated */
+ break;
default:
- opts.reset = 1;
+ BUG("invalid reset_type passed to reset_index");
}
- read_cache_unmerged();
+ repo_read_index_unmerged(the_repository);
if (reset_type == KEEP) {
struct object_id head_oid;
- if (get_oid("HEAD", &head_oid))
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
return error(_("You do not have a valid HEAD."));
if (!fill_tree_descriptor(the_repository, desc + nr, &head_oid))
return error(_("Failed to find tree of HEAD."));
@@ -98,6 +116,10 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
if (reset_type == MIXED || reset_type == HARD) {
tree = parse_tree_indirect(oid);
+ if (!tree) {
+ error(_("unable to read tree (%s)"), oid_to_hex(oid));
+ goto out;
+ }
prime_cache_tree(the_repository, the_repository->index, tree);
}
@@ -114,7 +136,7 @@ static void print_new_head_line(struct commit *commit)
struct strbuf buf = STRBUF_INIT;
printf(_("HEAD is now at %s"),
- find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
+ repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
if (buf.len > 0)
@@ -124,31 +146,48 @@ static void print_new_head_line(struct commit *commit)
}
static void update_index_from_diff(struct diff_queue_struct *q,
- struct diff_options *opt, void *data)
+ struct diff_options *opt UNUSED,
+ void *data)
{
int i;
int intent_to_add = *(int *)data;
for (i = 0; i < q->nr; i++) {
+ int pos;
struct diff_filespec *one = q->queue[i]->one;
- int is_missing = !(one->mode && !is_null_oid(&one->oid));
+ int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
struct cache_entry *ce;
- if (is_missing && !intent_to_add) {
- remove_file_from_cache(one->path);
+ if (!is_in_reset_tree && !intent_to_add) {
+ remove_file_from_index(&the_index, one->path);
continue;
}
ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
0, 0);
+
+ /*
+ * If the file 1) corresponds to an existing index entry with
+ * skip-worktree set, or 2) does not exist in the index but is
+ * outside the sparse checkout definition, add a skip-worktree bit
+ * to the new index entry. Note that a sparse index will be expanded
+ * if this entry is outside the sparse cone - this is necessary
+ * to properly construct the reset sparse directory.
+ */
+ pos = index_name_pos(&the_index, one->path, strlen(one->path));
+ if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
+ (pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
+ ce->ce_flags |= CE_SKIP_WORKTREE;
+
if (!ce)
die(_("make_cache_entry failed for path '%s'"),
one->path);
- if (is_missing) {
+ if (!is_in_reset_tree) {
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+ add_index_entry(&the_index, ce,
+ ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
}
}
@@ -164,13 +203,18 @@ static int read_from_tree(const struct pathspec *pathspec,
opt.format_callback = update_index_from_diff;
opt.format_callback_data = &intent_to_add;
opt.flags.override_submodule_config = 1;
+ opt.flags.recursive = 1;
opt.repo = the_repository;
+ opt.change = diff_change;
+ opt.add_remove = diff_addremove;
+
+ if (pathspec->nr && pathspec_needs_expanded_index(&the_index, pathspec))
+ ensure_full_index(&the_index);
if (do_diff_cache(tree_oid, &opt))
return 1;
diffcore_std(&opt);
diff_flush(&opt);
- clear_pathspec(&opt.pathspec);
return 0;
}
@@ -191,7 +235,7 @@ static void set_reflog_message(struct strbuf *sb, const char *action,
static void die_if_unmerged_cache(int reset_type)
{
- if (is_merge() || unmerged_cache())
+ if (is_merge() || unmerged_index(&the_index))
die(_("Cannot do a %s reset in the middle of a merge."),
_(reset_type_names[reset_type]));
@@ -228,8 +272,8 @@ static void parse_args(struct pathspec *pathspec,
* has to be unambiguous. If there is a single argument, it
* can not be a tree
*/
- else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
- (argv[1] && !get_oid_treeish(argv[0], &unused))) {
+ else if ((!argv[1] && !repo_get_oid_committish(the_repository, argv[0], &unused)) ||
+ (argv[1] && !repo_get_oid_treeish(the_repository, argv[0], &unused))) {
/*
* Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
@@ -241,10 +285,9 @@ static void parse_args(struct pathspec *pathspec,
verify_filename(prefix, argv[0], 1);
}
}
- *rev_ret = rev;
- if (read_cache() < 0)
- die(_("index file corrupt"));
+ /* treat '@' as a shortcut for 'HEAD' */
+ *rev_ret = !strcmp("@", rev) ? "HEAD" : rev;
parse_pathspec(pathspec, 0,
PATHSPEC_PREFER_FULL |
@@ -259,9 +302,9 @@ static int reset_refs(const char *rev, const struct object_id *oid)
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
- if (!get_oid("ORIG_HEAD", &oid_old_orig))
+ if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
old_orig = &oid_old_orig;
- if (!get_oid("HEAD", &oid_orig)) {
+ if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
@@ -275,36 +318,48 @@ static int reset_refs(const char *rev, const struct object_id *oid)
return update_ref_status;
}
-static int git_reset_config(const char *var, const char *value, void *cb)
+static int git_reset_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "submodule.recurse"))
return git_default_submodule_config(var, value, cb);
- return git_default_config(var, value, cb);
+ return git_default_config(var, value, ctx, cb);
}
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
+ int no_refresh = 0;
int patch_mode = 0, pathspec_file_nul = 0, unborn;
- const char *rev, *pathspec_from_file = NULL;
+ const char *rev;
+ char *pathspec_from_file = NULL;
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
- OPT_SET_INT(0, "mixed", &reset_type,
- N_("reset HEAD and index"), MIXED),
- OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
- OPT_SET_INT(0, "hard", &reset_type,
- N_("reset HEAD, index and working tree"), HARD),
- OPT_SET_INT(0, "merge", &reset_type,
- N_("reset HEAD, index and working tree"), MERGE),
- OPT_SET_INT(0, "keep", &reset_type,
- N_("reset HEAD but keep local changes"), KEEP),
+ OPT_BOOL(0, "no-refresh", &no_refresh,
+ N_("skip refreshing the index after reset")),
+ OPT_SET_INT_F(0, "mixed", &reset_type,
+ N_("reset HEAD and index"),
+ MIXED, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "soft", &reset_type,
+ N_("reset only HEAD"),
+ SOFT, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "hard", &reset_type,
+ N_("reset HEAD, index and working tree"),
+ HARD, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "merge", &reset_type,
+ N_("reset HEAD, index and working tree"),
+ MERGE, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "keep", &reset_type,
+ N_("reset HEAD but keep local changes"),
+ KEEP, PARSE_OPT_NONEG),
OPT_CALLBACK_F(0, "recurse-submodules", NULL,
- "reset", "control recursive updating of submodules",
- PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+ "reset", "control recursive updating of submodules",
+ PARSE_OPT_OPTARG,
+ option_parse_recurse_submodules_worktree_updater),
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_BOOL('N', "intent-to-add", &intent_to_add,
N_("record only the fact that removed paths will be added later")),
@@ -314,7 +369,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
};
git_config(git_reset_config, NULL);
- git_config_get_bool("reset.quiet", &quiet);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -322,25 +376,26 @@ int cmd_reset(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 (pathspec.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(&pathspec, 0,
PATHSPEC_PREFER_FULL,
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");
}
- unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
+ unborn = !strcmp(rev, "HEAD") && repo_get_oid(the_repository, "HEAD",
+ &oid);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
oidcpy(&oid, the_hash_algo->empty_tree);
} else if (!pathspec.nr && !patch_mode) {
struct commit *commit;
- if (get_oid_committish(rev, &oid))
+ if (repo_get_oid_committish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
@@ -348,7 +403,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
oidcpy(&oid, &commit->object.oid);
} else {
struct tree *tree;
- if (get_oid_treeish(rev, &oid))
+ if (repo_get_oid_treeish(the_repository, rev, &oid))
die(_("Failed to resolve '%s' as a valid tree."), rev);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -358,9 +413,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (patch_mode) {
if (reset_type != NONE)
- die(_("--patch is incompatible with --{hard,mixed,soft}"));
+ die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
trace2_cmd_mode("patch-interactive");
- return run_add_interactive(rev, "--patch=reset", &pathspec);
+ update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
+ &pathspec);
+ goto cleanup;
}
/* git reset tree [--] paths... can be used to
@@ -389,7 +446,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
_(reset_type_names[reset_type]));
if (intent_to_add && reset_type != MIXED)
- die(_("-N can only be used with --mixed"));
+ die(_("the option '%s' requires '%s'"), "-N", "--mixed");
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
+ if (repo_read_index(the_repository) < 0)
+ die(_("index file corrupt"));
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
@@ -399,23 +462,25 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type != SOFT) {
struct lock_file lock = LOCK_INIT;
- hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock,
+ LOCK_DIE_ON_ERROR);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- if (read_from_tree(&pathspec, &oid, intent_to_add))
- return 1;
+ if (read_from_tree(&pathspec, &oid, intent_to_add)) {
+ update_ref_status = 1;
+ goto cleanup;
+ }
the_index.updated_skipworktree = 1;
- if (!quiet && get_git_work_tree()) {
+ if (!no_refresh && get_git_work_tree()) {
uint64_t t_begin, t_delta_in_ms;
t_begin = getnanotime();
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
- if (advice_reset_quiet_warning && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
- printf(_("\nIt took %.2f seconds to enumerate unstaged changes after reset. You can\n"
- "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n"
- "to make this the default.\n"), t_delta_in_ms / 1000.0);
+ if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
+ advise(_("It took %.2f seconds to refresh the index after reset. You can use\n"
+ "'--no-refresh' to avoid this."), t_delta_in_ms / 1000.0);
}
}
} else {
@@ -423,9 +488,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
char *ref = NULL;
int err;
- dwim_ref(rev, strlen(rev), &dummy, &ref);
+ repo_dwim_ref(the_repository, rev, strlen(rev),
+ &dummy, &ref, 0);
if (ref && !starts_with(ref, "refs/"))
- ref = NULL;
+ FREE_AND_NULL(ref);
err = reset_index(ref, &oid, reset_type, quiet);
if (reset_type == KEEP && !err)
@@ -450,5 +516,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
+ discard_index(&the_index);
+
+cleanup:
+ clear_pathspec(&pathspec);
+ free(pathspec_from_file);
return update_ref_status;
}