Merge branch 'jc/checkout'
* 'jc/checkout': checkout: "best effort" checkout unpack_trees(): allow callers to differentiate worktree errors from merge errors checkout: consolidate reset_{to_new,clean_to_new}() checkout: make reset_clean_to_new() not die by itself
This commit is contained in:
@ -151,57 +151,50 @@ static void describe_detached_head(char *msg, struct commit *commit)
|
|||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reset_to_new(struct tree *tree, int quiet)
|
|
||||||
{
|
|
||||||
struct unpack_trees_options opts;
|
|
||||||
struct tree_desc tree_desc;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_clean_to_new(struct tree *tree, int quiet)
|
|
||||||
{
|
|
||||||
struct unpack_trees_options opts;
|
|
||||||
struct tree_desc tree_desc;
|
|
||||||
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
opts.head_idx = -1;
|
|
||||||
opts.skip_unmerged = 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))
|
|
||||||
exit(128);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct checkout_opts {
|
struct checkout_opts {
|
||||||
int quiet;
|
int quiet;
|
||||||
int merge;
|
int merge;
|
||||||
int force;
|
int force;
|
||||||
|
int writeout_error;
|
||||||
|
|
||||||
char *new_branch;
|
char *new_branch;
|
||||||
int new_branch_log;
|
int new_branch_log;
|
||||||
enum branch_track track;
|
enum branch_track track;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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.update = worktree;
|
||||||
|
opts.skip_unmerged = !worktree;
|
||||||
|
opts.reset = 1;
|
||||||
|
opts.merge = 1;
|
||||||
|
opts.fn = oneway_merge;
|
||||||
|
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);
|
||||||
|
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 branch_info {
|
struct branch_info {
|
||||||
const char *name; /* The short name used */
|
const char *name; /* The short name used */
|
||||||
const char *path; /* The full name of a real branch */
|
const char *path; /* The full name of a real branch */
|
||||||
@ -226,7 +219,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
|||||||
read_cache();
|
read_cache();
|
||||||
|
|
||||||
if (opts->force) {
|
if (opts->force) {
|
||||||
ret = reset_to_new(new->commit->tree, opts->quiet);
|
ret = reset_tree(new->commit->tree, opts, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
@ -262,7 +255,8 @@ static int merge_working_tree(struct checkout_opts *opts,
|
|||||||
tree = parse_tree_indirect(new->commit->object.sha1);
|
tree = parse_tree_indirect(new->commit->object.sha1);
|
||||||
init_tree_desc(&trees[1], tree->buffer, tree->size);
|
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
|
* Unpack couldn't do a trivial merge; either
|
||||||
* give up or do a real merge, depending on
|
* give up or do a real merge, depending on
|
||||||
@ -290,12 +284,14 @@ static int merge_working_tree(struct checkout_opts *opts,
|
|||||||
add_files_to_cache(NULL, NULL, 0);
|
add_files_to_cache(NULL, NULL, 0);
|
||||||
work = write_tree_from_memory();
|
work = write_tree_from_memory();
|
||||||
|
|
||||||
ret = reset_to_new(new->commit->tree, opts->quiet);
|
ret = reset_tree(new->commit->tree, opts, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
merge_trees(new->commit->tree, work, old->commit->tree,
|
merge_trees(new->commit->tree, work, old->commit->tree,
|
||||||
new->name, "local", &result);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +491,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
|||||||
|
|
||||||
update_refs_for_switch(opts, &old, 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)
|
int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||||
|
@ -358,8 +358,13 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N-way merge "len" trees. Returns 0 on success, -1 on failure to manipulate the
|
||||||
|
* resulting index, -2 on failure to reflect the changes to the work tree.
|
||||||
|
*/
|
||||||
int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
|
int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
static struct cache_entry *dfc;
|
static struct cache_entry *dfc;
|
||||||
|
|
||||||
if (len > MAX_UNPACK_TREES)
|
if (len > MAX_UNPACK_TREES)
|
||||||
@ -404,11 +409,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
|
|||||||
return unpack_failed(o, "Merge requires file-level merging");
|
return unpack_failed(o, "Merge requires file-level merging");
|
||||||
|
|
||||||
o->src_index = NULL;
|
o->src_index = NULL;
|
||||||
if (check_updates(o))
|
ret = check_updates(o) ? (-2) : 0;
|
||||||
return -1;
|
|
||||||
if (o->dst_index)
|
if (o->dst_index)
|
||||||
*o->dst_index = o->result;
|
*o->dst_index = o->result;
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Here come the merge functions */
|
/* Here come the merge functions */
|
||||||
|
Reference in New Issue
Block a user