summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/checkout.c74
1 files changed, 68 insertions, 6 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 1753c8c5ed..e855c64cfe 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -66,6 +66,8 @@ struct checkout_opts {
int can_switch_when_in_progress;
int orphan_from_empty_tree;
int empty_pathspec_ok;
+ int checkout_index;
+ int checkout_worktree;
const char *new_branch;
const char *new_branch_force;
@@ -397,6 +399,7 @@ static int checkout_paths(const struct checkout_opts *opts,
struct commit *head;
int errs = 0;
struct lock_file lock_file = LOCK_INIT;
+ int checkout_index;
trace2_cmd_mode(opts->patch_mode ? "patch" : "path");
@@ -422,9 +425,26 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("Cannot update paths and switch to branch '%s' at the same time."),
opts->new_branch);
- if (opts->patch_mode)
- return run_add_interactive(revision, "--patch=checkout",
- &opts->pathspec);
+ if (!opts->checkout_worktree && !opts->checkout_index)
+ die(_("neither '%s' or '%s' is specified"),
+ "--staged", "--worktree");
+
+ if (!opts->checkout_worktree && !opts->from_treeish)
+ die(_("'%s' must be used when '%s' is not specified"),
+ "--worktree", "--source");
+
+ if (opts->patch_mode) {
+ const char *patch_mode;
+
+ if (opts->checkout_index && opts->checkout_worktree)
+ patch_mode = "--patch=checkout";
+ else if (opts->checkout_index && !opts->checkout_worktree)
+ patch_mode = "--patch=reset";
+ else
+ die(_("'%s' with only '%s' is not currently supported"),
+ "--patch", "--worktree");
+ return run_add_interactive(revision, patch_mode, &opts->pathspec);
+ }
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
if (read_cache_preload(&opts->pathspec) < 0)
@@ -482,10 +502,30 @@ static int checkout_paths(const struct checkout_opts *opts,
return 1;
/* Now we are committed to check them out */
- errs |= checkout_worktree(opts);
+ if (opts->checkout_worktree)
+ errs |= checkout_worktree(opts);
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("unable to write new index file"));
+ /*
+ * Allow updating the index when checking out from the index.
+ * This is to save new stat info.
+ */
+ if (opts->checkout_worktree && !opts->checkout_index && !opts->source_tree)
+ checkout_index = 1;
+ else
+ checkout_index = opts->checkout_index;
+
+ if (checkout_index) {
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+ die(_("unable to write new index file"));
+ } else {
+ /*
+ * NEEDSWORK: if --worktree is not specified, we
+ * should save stat info of checked out files in the
+ * index to avoid the next (potentially costly)
+ * refresh. But it's a bit tricker to do...
+ */
+ rollback_lock_file(&lock_file);
+ }
read_ref_full("HEAD", 0, &rev, NULL);
head = lookup_commit_reference_gently(the_repository, &rev, 1);
@@ -1461,6 +1501,20 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->overlay_mode == 1 && opts->patch_mode)
die(_("-p and --overlay are mutually exclusive"));
+ if (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {
+ if (opts->checkout_index < 0)
+ opts->checkout_index = 0;
+ if (opts->checkout_worktree < 0)
+ opts->checkout_worktree = 0;
+ } else {
+ if (opts->checkout_index < 0)
+ opts->checkout_index = -opts->checkout_index - 1;
+ if (opts->checkout_worktree < 0)
+ opts->checkout_worktree = -opts->checkout_worktree - 1;
+ }
+ if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
+ BUG("these flags should be non-negative by now");
+
/*
* From here on, new_branch will contain the branch to be checked out,
* and new_branch_force and new_orphan_branch will tell us which one of
@@ -1617,6 +1671,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.orphan_from_empty_tree = 0;
opts.empty_pathspec_ok = 1;
opts.overlay_mode = -1;
+ opts.checkout_index = -2; /* default on */
+ opts.checkout_worktree = -2; /* default on */
options = parse_options_dup(checkout_options);
options = add_common_options(&opts, options);
@@ -1674,6 +1730,10 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
struct option restore_options[] = {
OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
N_("where the checkout from")),
+ OPT_BOOL('S', "staged", &opts.checkout_index,
+ N_("restore the index")),
+ OPT_BOOL('W', "worktree", &opts.checkout_worktree,
+ N_("restore the working tree (default)")),
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
OPT_END()
};
@@ -1684,6 +1744,8 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
opts.accept_pathspec = 1;
opts.empty_pathspec_ok = 0;
opts.overlay_mode = 0;
+ opts.checkout_index = -1; /* default off */
+ opts.checkout_worktree = -2; /* default on */
options = parse_options_dup(restore_options);
options = add_common_options(&opts, options);