NULL,
};
+static const char * const switch_branch_usage[] = {
+ N_("git switch [<options>] [<branch>]"),
+ NULL,
+};
+
struct checkout_opts {
int patch_mode;
int quiet;
int count_checkout_paths;
int overlay_mode;
int no_dwim_new_local_branch;
+ int discard_changes;
+ int accept_pathspec;
+ int switch_branch_doing_nothing_is_ok;
/*
* If new checkout options are added, skip_merge_working_tree
return error(_("index file corrupt"));
resolve_undo_clear();
- if (opts->force) {
+ if (opts->discard_changes) {
ret = reset_tree(get_commit_tree(new_branch_info->commit),
opts, 1, writeout_error);
if (ret)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- if (!opts->force && !opts->quiet)
+ if (!opts->discard_changes && !opts->quiet)
show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
return 0;
if (!argc)
return 0;
+ if (!opts->accept_pathspec) {
+ if (argc > 1)
+ die(_("only one reference expected"));
+ has_dash_dash = 1; /* helps disambiguate */
+ }
+
arg = argv[0];
dash_dash_pos = -1;
for (i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "--")) {
+ if (opts->accept_pathspec && !strcmp(argv[i], "--")) {
dash_dash_pos = i;
break;
}
recover_with_dwim = 0;
/*
- * Accept "git checkout foo" and "git checkout foo --"
- * as candidates for dwim.
+ * Accept "git checkout foo", "git checkout foo --"
+ * and "git switch foo" as candidates for dwim.
*/
if (!(argc == 1 && !has_dash_dash) &&
- !(argc == 2 && has_dash_dash))
+ !(argc == 2 && has_dash_dash) &&
+ opts->accept_pathspec)
recover_with_dwim = 0;
if (recover_with_dwim) {
*/
if (argc)
verify_non_filename(opts->prefix, arg);
- } else {
+ } else if (opts->accept_pathspec) {
argcount++;
argv++;
argc--;
if (opts->force && opts->merge)
die(_("'%s' cannot be used with '%s'"), "-f", "-m");
+ if (opts->discard_changes && opts->merge)
+ die(_("'%s' cannot be used with '%s'"), "--discard-changes", "--merge");
+
if (opts->force_detach && opts->new_branch)
die(_("'%s' cannot be used with '%s'"),
"--detach", "-b/-B/--orphan");
die(_("Cannot switch branch to a non-commit '%s'"),
new_branch_info->name);
+ if (!opts->switch_branch_doing_nothing_is_ok &&
+ !new_branch_info->name &&
+ !opts->new_branch &&
+ !opts->force_detach)
+ die(_("missing branch or commit argument"));
+
if (new_branch_info->path && !opts->force_detach && !opts->new_branch &&
!opts->ignore_other_worktrees) {
int flag;
return newopts;
}
-static struct option *add_switch_branch_options(struct checkout_opts *opts,
- struct option *prevopts)
+static struct option *add_common_switch_branch_options(
+ struct checkout_opts *opts, struct option *prevopts)
{
struct option options[] = {
- OPT_STRING('b', NULL, &opts->new_branch, N_("branch"),
- N_("create and checkout a new branch")),
- OPT_STRING('B', NULL, &opts->new_branch_force, N_("branch"),
- N_("create/reset and checkout a branch")),
- OPT_BOOL('l', NULL, &opts->new_branch_log, N_("create reflog for new branch")),
OPT_BOOL(0, "detach", &opts->force_detach, N_("detach HEAD at named commit")),
OPT_SET_INT('t', "track", &opts->track, N_("set upstream info for new branch"),
BRANCH_TRACK_EXPLICIT),
return newopts;
}
-int cmd_checkout(int argc, const char **argv, const char *prefix)
+static int checkout_main(int argc, const char **argv, const char *prefix,
+ struct checkout_opts *opts, struct option *options,
+ const char * const usagestr[])
{
- struct checkout_opts real_opts;
- struct checkout_opts *opts = &real_opts;
struct branch_info new_branch_info;
int dwim_remotes_matched = 0;
int dwim_new_local_branch;
- struct option *options = NULL;
- memset(opts, 0, sizeof(*opts));
memset(&new_branch_info, 0, sizeof(new_branch_info));
opts->overwrite_ignore = 1;
opts->prefix = prefix;
opts->show_progress = -1;
opts->overlay_mode = -1;
- opts->no_dwim_new_local_branch = 0;
git_config(git_checkout_config, opts);
opts->track = BRANCH_TRACK_UNSPECIFIED;
- options = parse_options_dup(options);
- options = add_common_options(opts, options);
- options = add_switch_branch_options(opts, options);
- options = add_checkout_path_options(opts, options);
-
- argc = parse_options(argc, argv, prefix, options, checkout_usage,
+ argc = parse_options(argc, argv, prefix, options, usagestr,
PARSE_OPT_KEEP_DASHDASH);
dwim_new_local_branch = !opts->no_dwim_new_local_branch;
opts->merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", opts->conflict_style, NULL);
}
+ if (opts->force)
+ opts->discard_changes = 1;
if ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)
die(_("-b, -B and --orphan are mutually exclusive"));
return checkout_branch(opts, &new_branch_info);
}
}
+
+int cmd_checkout(int argc, const char **argv, const char *prefix)
+{
+ struct checkout_opts opts;
+ struct option *options;
+ struct option checkout_options[] = {
+ OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+ N_("create and checkout a new branch")),
+ OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+ N_("create/reset and checkout a branch")),
+ OPT_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+ OPT_END()
+ };
+ int ret;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.no_dwim_new_local_branch = 0;
+ opts.switch_branch_doing_nothing_is_ok = 1;
+ opts.accept_pathspec = 1;
+
+ options = parse_options_dup(checkout_options);
+ options = add_common_options(&opts, options);
+ options = add_common_switch_branch_options(&opts, options);
+ options = add_checkout_path_options(&opts, options);
+
+ ret = checkout_main(argc, argv, prefix, &opts,
+ options, checkout_usage);
+ FREE_AND_NULL(options);
+ return ret;
+}
+
+int cmd_switch(int argc, const char **argv, const char *prefix)
+{
+ struct checkout_opts opts;
+ struct option *options = NULL;
+ struct option switch_options[] = {
+ OPT_STRING('c', "create", &opts.new_branch, N_("branch"),
+ N_("create and switch to a new branch")),
+ OPT_STRING('C', "force-create", &opts.new_branch_force, N_("branch"),
+ N_("create/reset and switch to a branch")),
+ OPT_BOOL(0, "discard-changes", &opts.discard_changes,
+ N_("throw away local modifications")),
+ OPT_END()
+ };
+ int ret;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.no_dwim_new_local_branch = 0;
+ opts.accept_pathspec = 0;
+ opts.switch_branch_doing_nothing_is_ok = 0;
+
+ options = parse_options_dup(switch_options);
+ options = add_common_options(&opts, options);
+ options = add_common_switch_branch_options(&opts, options);
+
+ ret = checkout_main(argc, argv, prefix, &opts,
+ options, switch_branch_usage);
+ FREE_AND_NULL(options);
+ return ret;
+}