#include "tree.h"
#include "branch.h"
#include "parse-options.h"
+#include "unpack-trees.h"
+#include "cache-tree.h"
static const char * const git_reset_usage[] = {
"git reset [--mixed | --soft | --hard | --merge] [-q] [<commit>]",
static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet)
{
- int i = 0;
- const char *args[6];
+ int nr = 1;
+ int newfd;
+ struct tree_desc desc[2];
+ struct unpack_trees_options opts;
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
- args[i++] = "read-tree";
+ memset(&opts, 0, sizeof(opts));
+ opts.head_idx = 1;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
+ opts.fn = oneway_merge;
+ opts.merge = 1;
if (!quiet)
- args[i++] = "-v";
+ opts.verbose_update = 1;
switch (reset_type) {
case MERGE:
- args[i++] = "-u";
- args[i++] = "-m";
+ opts.update = 1;
break;
case HARD:
- args[i++] = "-u";
+ opts.update = 1;
/* fallthrough */
default:
- args[i++] = "--reset";
+ opts.reset = 1;
}
- args[i++] = sha1_to_hex(sha1);
- args[i] = NULL;
- return run_command_v_opt(args, RUN_GIT_CMD);
+ newfd = hold_locked_index(lock, 1);
+
+ read_cache_unmerged();
+
+ if (!fill_tree_descriptor(desc + nr - 1, sha1))
+ return error("Failed to find tree of %s.", sha1_to_hex(sha1));
+ if (unpack_trees(nr, desc, &opts))
+ return -1;
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_locked_index(lock))
+ return error("Could not write new index file.");
+
+ return 0;
}
static void print_new_head_line(struct commit *commit)
if (read_cache() < 0)
return error("Could not read index");
- result = refresh_cache(flags) ? 1 : 0;
+ result = refresh_index(&the_index, (flags), NULL, NULL,
+ "Unstaged changes after reset:") ? 1 : 0;
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(index_lock))
return error ("Could not refresh index");
}
}
+static int interactive_reset(const char *revision, const char **argv,
+ const char *prefix)
+{
+ const char **pathspec = NULL;
+
+ if (*argv)
+ pathspec = get_pathspec(prefix, argv);
+
+ return run_add_interactive(revision, "--patch=reset", pathspec);
+}
+
static int read_from_tree(const char *prefix, const char **argv,
unsigned char *tree_sha1, int refresh_flags)
{
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
+ int patch_mode = 0;
const char *rev = "HEAD";
unsigned char sha1[20], *orig = NULL, sha1_orig[20],
*old_orig = NULL, sha1_old_orig[20];
struct commit *commit;
char *reflog_action, msg[1024];
const struct option options[] = {
+ OPT__QUIET(&quiet),
OPT_SET_INT(0, "mixed", &reset_type,
"reset HEAD and index", MIXED),
OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
"reset HEAD, index and working tree", HARD),
OPT_SET_INT(0, "merge", &reset_type,
"reset HEAD, index and working tree", MERGE),
- OPT_BOOLEAN('q', NULL, &quiet,
- "disable showing new HEAD in hard reset and progress message"),
+ OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
OPT_END()
};
git_config(git_default_config, NULL);
- argc = parse_options(argc, argv, options, git_reset_usage,
+ argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
reflog_action = args_to_str(argv);
setenv("GIT_REFLOG_ACTION", reflog_action, 0);
}
/*
* Otherwise, argv[i] could be either <rev> or <paths> and
- * has to be unambigous.
+ * has to be unambiguous.
*/
else if (!get_sha1(argv[i], sha1)) {
/*
die("Could not parse object '%s'.", rev);
hashcpy(sha1, commit->object.sha1);
+ if (patch_mode) {
+ if (reset_type != NONE)
+ die("--patch is incompatible with --{hard,mixed,soft}");
+ return interactive_reset(rev, argv + i, prefix);
+ }
+
/* git reset tree [--] paths... can be used to
* load chosen paths from the tree into the index without
* affecting the working tree nor HEAD. */
die("Cannot do %s reset with paths.",
reset_type_names[reset_type]);
return read_from_tree(prefix, argv + i, sha1,
- quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+ quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
}
if (reset_type == NONE)
reset_type = MIXED; /* by default */
- if (reset_type == HARD && is_bare_repository())
- die("hard reset makes no sense in a bare repository");
+ if (reset_type == HARD || reset_type == MERGE)
+ setup_work_tree();
+
+ if (reset_type == MIXED && is_bare_repository())
+ die("%s reset is not allowed in a bare repository",
+ reset_type_names[reset_type]);
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
break;
case MIXED: /* Report what has not been updated. */
update_index_refresh(0, NULL,
- quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+ quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
break;
}