static const char * const git_reset_usage[] = {
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
- N_("git reset [-q] <commit> [--] <paths>..."),
- N_("git reset --patch [<commit>] [--] [<paths>...]"),
+ N_("git reset [-q] <tree-ish> [--] <paths>..."),
+ N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
NULL
};
printf("\n");
}
-static int update_index_refresh(int fd, struct lock_file *index_lock, int flags)
-{
- if (!index_lock) {
- index_lock = xcalloc(1, sizeof(struct lock_file));
- fd = hold_locked_index(index_lock, 1);
- }
-
- refresh_index(&the_index, (flags), NULL, NULL,
- _("Unstaged changes after reset:"));
- if (write_cache(fd, active_cache, active_nr) ||
- commit_locked_index(index_lock))
- return error ("Could not refresh index");
- return 0;
-}
-
static void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
/*
* Possible arguments are:
*
- * git reset [-opts] <rev> <paths>...
- * git reset [-opts] <rev> -- <paths>...
- * git reset [-opts] -- <paths>...
+ * git reset [-opts] [<rev>]
+ * git reset [-opts] <tree> [<paths>...]
+ * git reset [-opts] <tree> -- [<paths>...]
+ * git reset [-opts] -- [<paths>...]
* git reset [-opts] <paths>...
*
* At this point, argv points immediately after [-opts].
}
/*
* Otherwise, argv[0] could be either <rev> or <paths> and
- * has to be unambiguous.
+ * has to be unambiguous. If there is a single argument, it
+ * can not be a tree
*/
- else if (!get_sha1_committish(argv[0], unused)) {
+ else if ((!argv[1] && !get_sha1_committish(argv[0], unused)) ||
+ (argv[1] && !get_sha1_treeish(argv[0], unused))) {
/*
- * Ok, argv[0] looks like a rev; it should not
+ * Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
*/
verify_non_filename(prefix, argv[0]);
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
- int patch_mode = 0;
+ int patch_mode = 0, unborn;
const char *rev;
unsigned char sha1[20];
const char **pathspec = NULL;
- struct commit *commit;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
PARSE_OPT_KEEP_DASHDASH);
pathspec = parse_args(argv, prefix, &rev);
- if (get_sha1_committish(rev, sha1))
- die(_("Failed to resolve '%s' as a valid ref."), rev);
-
- /*
- * NOTE: As "git reset $treeish -- $path" should be usable on
- * any tree-ish, this is not strictly correct. We are not
- * moving the HEAD to any commit; we are merely resetting the
- * entries in the index to that of a treeish.
- */
- commit = lookup_commit_reference(sha1);
- if (!commit)
- die(_("Could not parse object '%s'."), rev);
- hashcpy(sha1, commit->object.sha1);
+ unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
+ if (unborn) {
+ /* reset on unborn branch: treat as reset to empty tree */
+ hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
+ } else if (!pathspec) {
+ struct commit *commit;
+ if (get_sha1_committish(rev, sha1))
+ die(_("Failed to resolve '%s' as a valid revision."), rev);
+ commit = lookup_commit_reference(sha1);
+ if (!commit)
+ die(_("Could not parse object '%s'."), rev);
+ hashcpy(sha1, commit->object.sha1);
+ } else {
+ struct tree *tree;
+ if (get_sha1_treeish(rev, sha1))
+ die(_("Failed to resolve '%s' as a valid tree."), rev);
+ tree = parse_tree_indirect(sha1);
+ if (!tree)
+ die(_("Could not parse object '%s'."), rev);
+ hashcpy(sha1, tree->object.sha1);
+ }
if (patch_mode) {
if (reset_type != NONE)
die(_("--patch is incompatible with --{hard,mixed,soft}"));
- return run_add_interactive(rev, "--patch=reset", pathspec);
+ return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec);
}
/* git reset tree [--] paths... can be used to
die(_("%s reset is not allowed in a bare repository"),
_(reset_type_names[reset_type]));
- if (pathspec) {
- struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
- int index_fd = hold_locked_index(lock, 1);
- return read_from_tree(pathspec, sha1) ||
- update_index_refresh(index_fd, lock,
- quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
- }
-
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
* the index file to the tree object we are switching to. */
if (reset_type != SOFT) {
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock, 1);
- int err = reset_index(sha1, reset_type, quiet);
- if (reset_type == KEEP && !err)
- err = reset_index(sha1, MIXED, quiet);
- if (err)
- die(_("Could not reset index file to revision '%s'."), rev);
+ if (reset_type == MIXED) {
+ if (read_from_tree(pathspec, sha1))
+ return 1;
+ } else {
+ int err = reset_index(sha1, reset_type, quiet);
+ if (reset_type == KEEP && !err)
+ err = reset_index(sha1, MIXED, quiet);
+ if (err)
+ die(_("Could not reset index file to revision '%s'."), rev);
+ }
+
+ if (reset_type == MIXED) { /* Report what has not been updated. */
+ int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
+ refresh_index(&the_index, flags, NULL, NULL,
+ _("Unstaged changes after reset:"));
+ }
+
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(lock))
die(_("Could not write new index file."));
}
- /* Any resets update HEAD to the head being switched to,
- * saving the previous head in ORIG_HEAD before. */
- update_ref_status = update_refs(rev, sha1);
+ if (!pathspec && !unborn) {
+ /* Any resets without paths update HEAD to the head being
+ * switched to, saving the previous head in ORIG_HEAD before. */
+ update_ref_status = update_refs(rev, sha1);
- if (reset_type == HARD && !update_ref_status && !quiet)
- print_new_head_line(commit);
- else if (reset_type == MIXED) /* Report what has not been updated. */
- update_index_refresh(0, NULL,
- quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
-
- remove_branch_state();
+ if (reset_type == HARD && !update_ref_status && !quiet)
+ print_new_head_line(lookup_commit_reference(sha1));
+ }
+ if (!pathspec)
+ remove_branch_state();
return update_ref_status;
}