aboutsummaryrefslogtreecommitdiff
path: root/builtin/checkout.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/checkout.c')
-rw-r--r--builtin/checkout.c139
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);
}