diff options
Diffstat (limited to 'builtin-checkout.c')
-rw-r--r-- | builtin-checkout.c | 90 |
1 files changed, 46 insertions, 44 deletions
diff --git a/builtin-checkout.c b/builtin-checkout.c index cf9875c13d..93ea69bfaa 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -84,6 +84,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) unsigned char rev[20]; int flag; struct commit *head; + int errs = 0; int newfd; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); @@ -106,13 +107,14 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) if (report_path_error(ps_matched, pathspec, 0)) return 1; + /* Now we are committed to check them out */ memset(&state, 0, sizeof(state)); state.force = 1; state.refresh_cache = 1; for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (pathspec_match(pathspec, NULL, ce->name, 0)) { - checkout_entry(ce, &state, NULL); + errs |= checkout_entry(ce, &state, NULL); } } @@ -123,7 +125,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) resolve_ref("HEAD", rev, 0, &flag); head = lookup_commit_reference_gently(rev, 1); - return post_checkout_hook(head, head, 0); + errs |= post_checkout_hook(head, head, 0); + return errs; } static void show_local_changes(struct object *head) @@ -148,57 +151,50 @@ static void describe_detached_head(char *msg, struct commit *commit) strbuf_release(&sb); } -static int reset_to_new(struct tree *tree, int quiet) -{ - struct unpack_trees_options opts; - struct tree_desc tree_desc; +struct checkout_opts { + int quiet; + int merge; + int force; + int writeout_error; - memset(&opts, 0, sizeof(opts)); - opts.head_idx = -1; - opts.update = 1; - opts.reset = 1; - opts.merge = 1; - opts.fn = oneway_merge; - opts.verbose_update = !quiet; - opts.src_index = &the_index; - opts.dst_index = &the_index; - parse_tree(tree); - init_tree_desc(&tree_desc, tree->buffer, tree->size); - if (unpack_trees(1, &tree_desc, &opts)) - return 128; - return 0; -} + char *new_branch; + int new_branch_log; + enum branch_track track; +}; -static void reset_clean_to_new(struct tree *tree, int quiet) +static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree) { struct unpack_trees_options opts; struct tree_desc tree_desc; memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; - opts.skip_unmerged = 1; + opts.update = worktree; + opts.skip_unmerged = !worktree; opts.reset = 1; opts.merge = 1; opts.fn = oneway_merge; - opts.verbose_update = !quiet; + opts.verbose_update = !o->quiet; opts.src_index = &the_index; opts.dst_index = &the_index; parse_tree(tree); init_tree_desc(&tree_desc, tree->buffer, tree->size); - if (unpack_trees(1, &tree_desc, &opts)) - exit(128); + switch (unpack_trees(1, &tree_desc, &opts)) { + case -2: + o->writeout_error = 1; + /* + * We return 0 nevertheless, as the index is all right + * and more importantly we have made best efforts to + * update paths in the work tree, and we cannot revert + * them. + */ + case 0: + return 0; + default: + return 128; + } } -struct checkout_opts { - int quiet; - int merge; - int force; - - char *new_branch; - int new_branch_log; - enum branch_track track; -}; - struct branch_info { const char *name; /* The short name used */ const char *path; /* The full name of a real branch */ @@ -223,7 +219,7 @@ static int merge_working_tree(struct checkout_opts *opts, read_cache(); if (opts->force) { - ret = reset_to_new(new->commit->tree, opts->quiet); + ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; } else { @@ -236,6 +232,8 @@ static int merge_working_tree(struct checkout_opts *opts, topts.src_index = &the_index; topts.dst_index = &the_index; + topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches."; + refresh_cache(REFRESH_QUIET); if (unmerged_cache()) { @@ -257,7 +255,8 @@ static int merge_working_tree(struct checkout_opts *opts, tree = parse_tree_indirect(new->commit->object.sha1); init_tree_desc(&trees[1], tree->buffer, tree->size); - if (unpack_trees(2, trees, &topts)) { + ret = unpack_trees(2, trees, &topts); + if (ret == -1) { /* * Unpack couldn't do a trivial merge; either * give up or do a real merge, depending on @@ -282,15 +281,17 @@ static int merge_working_tree(struct checkout_opts *opts, * entries in the index. */ - add_files_to_cache(0, NULL, NULL); + add_files_to_cache(NULL, NULL, 0); work = write_tree_from_memory(); - ret = reset_to_new(new->commit->tree, opts->quiet); + ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; merge_trees(new->commit->tree, work, old->commit->tree, new->name, "local", &result); - reset_clean_to_new(new->commit->tree, opts->quiet); + ret = reset_tree(new->commit->tree, opts, 0); + if (ret) + return ret; } } @@ -490,7 +491,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) update_refs_for_switch(opts, &old, new); - return post_checkout_hook(old.commit, new->commit, 1); + ret = post_checkout_hook(old.commit, new->commit, 1); + return ret || opts->writeout_error; } int cmd_checkout(int argc, const char **argv, const char *prefix) @@ -504,7 +506,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT__QUIET(&opts.quiet), OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"), OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"), - OPT_SET_INT( 0 , "track", &opts.track, "track", + OPT_SET_INT('t', "track", &opts.track, "track", BRANCH_TRACK_EXPLICIT), OPT_BOOLEAN('f', NULL, &opts.force, "force"), OPT_BOOLEAN('m', NULL, &opts.merge, "merge"), @@ -514,7 +516,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); - git_config(git_default_config); + git_config(git_default_config, NULL); opts.track = git_branch_track; |