diff options
Diffstat (limited to 'builtin/checkout.c')
| -rw-r--r-- | builtin/checkout.c | 139 |
1 files changed, 95 insertions, 44 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c index f9453473fe..e031e61886 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -43,26 +43,11 @@ #include "parallel-checkout.h" #include "add-interactive.h" -static const char * const checkout_usage[] = { - N_("git checkout [<options>] <branch>"), - N_("git checkout [<options>] [<branch>] -- <file>..."), - NULL, -}; - -static const char * const switch_branch_usage[] = { - N_("git switch [<options>] [<branch>]"), - NULL, -}; - -static const char * const restore_usage[] = { - N_("git restore [<options>] [--source=<branch>] <file>..."), - NULL, -}; - struct checkout_opts { int patch_mode; int patch_context; int patch_interhunk_context; + int auto_advance; int quiet; int merge; int force; @@ -111,6 +96,7 @@ struct checkout_opts { .merge = -1, \ .patch_context = -1, \ .patch_interhunk_context = -1, \ + .auto_advance = 1, \ } struct branch_info { @@ -294,9 +280,9 @@ static int checkout_merged(int pos, const struct checkout *state, if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2])) return error(_("path '%s' does not have necessary versions"), path); - read_mmblob(&ancestor, &threeway[0]); - read_mmblob(&ours, &threeway[1]); - read_mmblob(&theirs, &threeway[2]); + read_mmblob(&ancestor, the_repository->objects, &threeway[0]); + read_mmblob(&ours, the_repository->objects, &threeway[1]); + read_mmblob(&theirs, the_repository->objects, &threeway[2]); repo_config_get_bool(the_repository, "merge.renormalize", &renormalize); ll_opts.renormalize = renormalize; @@ -546,9 +532,10 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->patch_mode) { enum add_p_mode patch_mode; - struct add_p_opt add_p_opt = { + struct interactive_options interactive_opts = { .context = opts->patch_context, .interhunkcontext = opts->patch_interhunk_context, + .auto_advance = opts->auto_advance }; const char *rev = new_branch_info->name; char rev_oid[GIT_MAX_HEXSZ + 1]; @@ -575,8 +562,8 @@ static int checkout_paths(const struct checkout_opts *opts, else BUG("either flag must have been set, worktree=%d, index=%d", opts->checkout_worktree, opts->checkout_index); - return !!run_add_p(the_repository, patch_mode, &add_p_opt, - rev, &opts->pathspec); + return !!run_add_p(the_repository, patch_mode, &interactive_opts, + rev, &opts->pathspec, 0); } repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); @@ -724,7 +711,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o, init_checkout_metadata(&opts.meta, info->refname, info->commit ? &info->commit->object.oid : null_oid(the_hash_algo), NULL); - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) return 128; init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size); switch (unpack_trees(1, &tree_desc, &opts)) { @@ -803,7 +790,8 @@ static int merge_working_tree(const struct checkout_opts *opts, if (opts->new_orphan_branch && opts->orphan_from_empty_tree) { if (new_branch_info->commit) BUG("'switch --orphan' should never accept a commit as starting point"); - new_tree = parse_tree_indirect(the_hash_algo->empty_tree); + new_tree = repo_parse_tree_indirect(the_repository, + the_hash_algo->empty_tree); if (!new_tree) BUG("unable to read empty tree"); } else { @@ -841,14 +829,15 @@ static int merge_working_tree(const struct checkout_opts *opts, old_commit_oid = old_branch_info->commit ? &old_branch_info->commit->object.oid : the_hash_algo->empty_tree; - tree = parse_tree_indirect(old_commit_oid); + tree = repo_parse_tree_indirect(the_repository, + old_commit_oid); if (!tree) die(_("unable to parse commit %s"), oid_to_hex(old_commit_oid)); init_tree_desc(&trees[0], &tree->object.oid, tree->buffer, tree->size); - if (parse_tree(new_tree) < 0) + if (repo_parse_tree(the_repository, new_tree) < 0) die(NULL); tree = new_tree; init_tree_desc(&trees[1], &tree->object.oid, @@ -899,10 +888,11 @@ static int merge_working_tree(const struct checkout_opts *opts, */ add_files_to_cache(the_repository, NULL, NULL, NULL, 0, - 0); + 0, 0); init_ui_merge_options(&o, the_repository); o.verbosity = 0; - work = write_in_core_index_as_tree(the_repository); + work = write_in_core_index_as_tree(the_repository, + the_repository->index); ret = reset_tree(new_tree, opts, 1, @@ -1063,11 +1053,9 @@ static void update_refs_for_switch(const struct checkout_opts *opts, report_tracking(new_branch_info); } -static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED, - const struct object_id *oid, - int flags UNUSED, void *cb_data) +static int add_pending_uninteresting_ref(const struct reference *ref, void *cb_data) { - add_pending_oid(cb_data, refname, oid, UNINTERESTING); + add_pending_oid(cb_data, ref->name, ref->oid, UNINTERESTING); return 0; } @@ -1280,7 +1268,7 @@ static void setup_new_branch_info_and_source_tree( new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1); if (!new_branch_info->commit) { /* not a commit */ - *source_tree = parse_tree_indirect(rev); + *source_tree = repo_parse_tree_indirect(the_repository, rev); if (!*source_tree) die(_("unable to read tree (%s)"), oid_to_hex(rev)); } else { @@ -1293,9 +1281,17 @@ static void setup_new_branch_info_and_source_tree( } } + +enum checkout_command { + CHECKOUT_CHECKOUT = 1, + CHECKOUT_SWITCH = 2, + CHECKOUT_RESTORE = 3, +}; + static char *parse_remote_branch(const char *arg, struct object_id *rev, - int could_be_checkout_paths) + int could_be_checkout_paths, + enum checkout_command which_command) { int num_matches = 0; char *remote = unique_tracking_name(arg, rev, &num_matches); @@ -1308,14 +1304,30 @@ static char *parse_remote_branch(const char *arg, if (!remote && num_matches > 1) { if (advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME)) { + const char *cmdname; + + switch (which_command) { + case CHECKOUT_CHECKOUT: + cmdname = "checkout"; + break; + case CHECKOUT_SWITCH: + cmdname = "switch"; + break; + default: + BUG("command <%d> should not reach parse_remote_branch", + which_command); + break; + } + advise(_("If you meant to check out a remote tracking branch on, e.g. 'origin',\n" "you can do so by fully qualifying the name with the --track option:\n" "\n" - " git checkout --track origin/<name>\n" + " git %s --track origin/<name>\n" "\n" "If you'd like to always have checkouts of an ambiguous <name> prefer\n" "one remote, e.g. the 'origin' remote, consider setting\n" - "checkout.defaultRemote=origin in your config.")); + "checkout.defaultRemote=origin in your config."), + cmdname); } die(_("'%s' matched multiple (%d) remote tracking branches"), @@ -1327,6 +1339,7 @@ static char *parse_remote_branch(const char *arg, static int parse_branchname_arg(int argc, const char **argv, int dwim_new_local_branch_ok, + enum checkout_command which_command, struct branch_info *new_branch_info, struct checkout_opts *opts, struct object_id *rev) @@ -1436,7 +1449,8 @@ static int parse_branchname_arg(int argc, const char **argv, if (recover_with_dwim) { remote = parse_remote_branch(arg, rev, - could_be_checkout_paths); + could_be_checkout_paths, + which_command); if (remote) { *new_branch = arg; arg = remote; @@ -1590,6 +1604,7 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts, static int checkout_branch(struct checkout_opts *opts, struct branch_info *new_branch_info) { + struct repo_config_values *cfg = repo_config_values(the_repository); int noop_switch = (!new_branch_info->name && !opts->new_branch && !opts->force_detach); @@ -1633,7 +1648,7 @@ static int checkout_branch(struct checkout_opts *opts, if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with '%s'"), "--detach", "-t"); } else if (opts->track == BRANCH_TRACK_UNSPECIFIED) - opts->track = git_branch_track; + opts->track = cfg->branch_track; if (new_branch_info->name && !new_branch_info->commit) die(_("Cannot switch branch to a non-commit '%s'"), @@ -1767,12 +1782,44 @@ static char cb_option = 'b'; static int checkout_main(int argc, const char **argv, const char *prefix, struct checkout_opts *opts, struct option *options, - const char * const usagestr[]) + enum checkout_command which_command) { int parseopt_flags = 0; struct branch_info new_branch_info = { 0 }; int ret; + static const char * const checkout_usage[] = { + N_("git checkout [<options>] <branch>"), + N_("git checkout [<options>] [<branch>] -- <file>..."), + NULL, + }; + + static const char * const switch_branch_usage[] = { + N_("git switch [<options>] [<branch>]"), + NULL, + }; + + static const char * const restore_usage[] = { + N_("git restore [<options>] [--source=<branch>] <file>..."), + NULL, + }; + + const char * const *usagestr; + + switch (which_command) { + case CHECKOUT_CHECKOUT: + usagestr = checkout_usage; + break; + case CHECKOUT_SWITCH: + usagestr = switch_branch_usage; + break; + case CHECKOUT_RESTORE: + usagestr = restore_usage; + break; + default: + BUG("no such checkout variant %d", which_command); + } + opts->overwrite_ignore = 1; opts->prefix = prefix; opts->show_progress = -1; @@ -1803,6 +1850,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix, die(_("the option '%s' requires '%s'"), "--unified", "--patch"); if (opts->patch_interhunk_context != -1) die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); + if (!opts->auto_advance) + die(_("the option '%s' requires '%s'"), "--no-auto-advance", "--patch"); } if (opts->show_progress < 0) { @@ -1893,7 +1942,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix, opts->dwim_new_local_branch && opts->track == BRANCH_TRACK_UNSPECIFIED && !opts->new_branch; - int n = parse_branchname_arg(argc, argv, dwim_ok, + int n = parse_branchname_arg(argc, argv, dwim_ok, which_command, &new_branch_info, opts, &rev); argv += n; argc -= n; @@ -1901,7 +1950,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix, struct object_id rev; if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev)) - die(_("could not resolve %s"), opts->from_treeish); + die(_("could not resolve '%s'"), opts->from_treeish); setup_new_branch_info_and_source_tree(&new_branch_info, opts, &rev, @@ -2001,6 +2050,8 @@ int cmd_checkout(int argc, OPT_BOOL(0, "guess", &opts.dwim_new_local_branch, N_("second guess 'git checkout <no-such-branch>' (default)")), OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")), + OPT_BOOL(0, "auto-advance", &opts.auto_advance, + N_("auto advance to the next file when selecting hunks interactively")), OPT_END() }; @@ -2032,7 +2083,7 @@ int cmd_checkout(int argc, options = add_checkout_path_options(&opts, options); return checkout_main(argc, argv, prefix, &opts, options, - checkout_usage); + CHECKOUT_CHECKOUT); } int cmd_switch(int argc, @@ -2071,7 +2122,7 @@ int cmd_switch(int argc, cb_option = 'c'; return checkout_main(argc, argv, prefix, &opts, options, - switch_branch_usage); + CHECKOUT_SWITCH); } int cmd_restore(int argc, @@ -2107,5 +2158,5 @@ int cmd_restore(int argc, options = add_checkout_path_options(&opts, options); return checkout_main(argc, argv, prefix, &opts, options, - restore_usage); + CHECKOUT_RESTORE); } |
