diff options
Diffstat (limited to 'merge-recursive.c')
-rw-r--r-- | merge-recursive.c | 152 |
1 files changed, 112 insertions, 40 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index b83a129..8ff29ed 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -3,14 +3,10 @@ * Fredrik Kuivinen. * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006 */ -#include "cache.h" +#include "git-compat-util.h" #include "merge-recursive.h" -#include "advice.h" #include "alloc.h" -#include "attr.h" -#include "blob.h" -#include "builtin.h" #include "cache-tree.h" #include "commit.h" #include "commit-reach.h" @@ -18,14 +14,22 @@ #include "diff.h" #include "diffcore.h" #include "dir.h" -#include "ll-merge.h" +#include "environment.h" +#include "gettext.h" +#include "hex.h" +#include "merge-ll.h" #include "lockfile.h" -#include "object-store.h" +#include "match-trees.h" +#include "name-hash.h" +#include "object-file.h" +#include "object-name.h" +#include "object-store-ll.h" +#include "path.h" #include "repository.h" #include "revision.h" +#include "sparse-index.h" #include "string-list.h" -#include "submodule-config.h" -#include "submodule.h" +#include "symlinks.h" #include "tag.h" #include "tree-walk.h" #include "unpack-trees.h" @@ -45,7 +49,7 @@ struct path_hashmap_entry { char path[FLEX_ARRAY]; }; -static int path_hashmap_cmp(const void *cmp_data, +static int path_hashmap_cmp(const void *cmp_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, const void *keydata) @@ -89,10 +93,10 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap, return hashmap_get_entry(hashmap, &key, ent, NULL); } -static int dir_rename_cmp(const void *unused_cmp_data, +static int dir_rename_cmp(const void *cmp_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, - const void *unused_keydata) + const void *keydata UNUSED) { const struct dir_rename_entry *e1, *e2; @@ -134,10 +138,10 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap, return hashmap_get_entry(hashmap, &key, ent, NULL); } -static int collision_cmp(const void *unused_cmp_data, +static int collision_cmp(const void *cmp_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, - const void *unused_keydata) + const void *keydata UNUSED) { const struct collision_entry *e1, *e2; @@ -401,8 +405,9 @@ static inline int merge_detect_rename(struct merge_options *opt) static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree) { - parse_tree(tree); - init_tree_desc(desc, tree->buffer, tree->size); + if (parse_tree(tree) < 0) + exit(128); + init_tree_desc(desc, &tree->object.oid, tree->buffer, tree->size); } static int unpack_trees_start(struct merge_options *opt, @@ -412,7 +417,7 @@ static int unpack_trees_start(struct merge_options *opt, { int rc; struct tree_desc t[3]; - struct index_state tmp_index = { NULL }; + struct index_state tmp_index = INDEX_STATE_INIT(opt->repo); memset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts)); if (opt->priv->call_depth) @@ -456,7 +461,7 @@ static void unpack_trees_finish(struct merge_options *opt) clear_unpack_trees_porcelain(&opt->priv->unpack_opts); } -static int save_files_dirs(const struct object_id *oid, +static int save_files_dirs(const struct object_id *oid UNUSED, struct strbuf *base, const char *path, unsigned int mode, void *context) { @@ -951,7 +956,8 @@ static int update_file_flags(struct merge_options *opt, goto update_index; } - buf = read_object_file(&contents->oid, &type, &size); + buf = repo_read_object_file(the_repository, &contents->oid, + &type, &size); if (!buf) { ret = err(opt, _("cannot read object %s '%s'"), oid_to_hex(&contents->oid), path); @@ -1042,13 +1048,14 @@ static int merge_3way(struct merge_options *opt, const int extra_marker_size) { mmfile_t orig, src1, src2; - struct ll_merge_options ll_opts = {0}; + struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT; char *base, *name1, *name2; enum ll_merge_result merge_status; ll_opts.renormalize = opt->renormalize; ll_opts.extra_marker_size = extra_marker_size; ll_opts.xdl_opts = opt->xdl_opts; + ll_opts.conflict_style = opt->conflict_style; if (opt->priv->call_depth) { ll_opts.virtual_ancestor = 1; @@ -1134,7 +1141,13 @@ static int find_first_merges(struct repository *repo, die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { struct object *o = &(commit->object); - if (repo_in_merge_bases(repo, b, commit)) + int ret = repo_in_merge_bases(repo, b, commit); + if (ret < 0) { + object_array_clear(&merges); + release_revisions(&revs); + return ret; + } + if (ret) add_object_array(o, NULL, &merges); } reset_revision_walk(); @@ -1149,9 +1162,17 @@ static int find_first_merges(struct repository *repo, contains_another = 0; for (j = 0; j < merges.nr; j++) { struct commit *m2 = (struct commit *) merges.objects[j].item; - if (i != j && repo_in_merge_bases(repo, m2, m1)) { - contains_another = 1; - break; + if (i != j) { + int ret = repo_in_merge_bases(repo, m2, m1); + if (ret < 0) { + object_array_clear(&merges); + release_revisions(&revs); + return ret; + } + if (ret > 0) { + contains_another = 1; + break; + } } } @@ -1187,7 +1208,7 @@ static int merge_submodule(struct merge_options *opt, const struct object_id *b) { struct repository subrepo; - int ret = 0; + int ret = 0, ret2; struct commit *commit_base, *commit_a, *commit_b; int parent_count; struct object_array merges; @@ -1224,14 +1245,32 @@ static int merge_submodule(struct merge_options *opt, } /* check whether both changes are forward */ - if (!repo_in_merge_bases(&subrepo, commit_base, commit_a) || - !repo_in_merge_bases(&subrepo, commit_base, commit_b)) { + ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a); + if (ret2 < 0) { + output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path); + ret = -1; + goto cleanup; + } + if (ret2 > 0) + ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b); + if (ret2 < 0) { + output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path); + ret = -1; + goto cleanup; + } + if (!ret2) { output(opt, 1, _("Failed to merge submodule %s (commits don't follow merge-base)"), path); goto cleanup; } /* Case #1: a is contained in b or vice versa */ - if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) { + ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b); + if (ret2 < 0) { + output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path); + ret = -1; + goto cleanup; + } + if (ret2) { oidcpy(result, b); if (show(opt, 3)) { output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path); @@ -1244,7 +1283,13 @@ static int merge_submodule(struct merge_options *opt, ret = 1; goto cleanup; } - if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) { + ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a); + if (ret2 < 0) { + output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path); + ret = -1; + goto cleanup; + } + if (ret2) { oidcpy(result, a); if (show(opt, 3)) { output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path); @@ -1273,6 +1318,10 @@ static int merge_submodule(struct merge_options *opt, parent_count = find_first_merges(&subrepo, &merges, path, commit_a, commit_b); switch (parent_count) { + case -1: + output(opt, 1,_("Failed to merge submodule %s (repository corrupt)"), path); + ret = -1; + break; case 0: output(opt, 1, _("Failed to merge submodule %s (merge following commits not found)"), path); break; @@ -1373,12 +1422,12 @@ static int merge_mode_and_contents(struct merge_options *opt, extra_marker_size); if ((merge_status < 0) || !result_buf.ptr) - ret = err(opt, _("Failed to execute internal merge")); + ret = err(opt, _("failed to execute internal merge")); if (!ret && write_object_file(result_buf.ptr, result_buf.size, OBJ_BLOB, &result->blob.oid)) - ret = err(opt, _("Unable to add %s to database"), + ret = err(opt, _("unable to add %s to database"), a->path); free(result_buf.ptr); @@ -1387,11 +1436,14 @@ static int merge_mode_and_contents(struct merge_options *opt, /* FIXME: bug, what if modes didn't match? */ result->clean = (merge_status == 0); } else if (S_ISGITLINK(a->mode)) { - result->clean = merge_submodule(opt, &result->blob.oid, - o->path, - &o->oid, - &a->oid, - &b->oid); + int clean = merge_submodule(opt, &result->blob.oid, + o->path, + &o->oid, + &a->oid, + &b->oid); + if (clean < 0) + return -1; + result->clean = clean; } else if (S_ISLNK(a->mode)) { switch (opt->recursive_variant) { case MERGE_VARIANT_NORMAL: @@ -2100,7 +2152,7 @@ static char *handle_path_level_conflicts(struct merge_options *opt, if (!new_path) { /* This should only happen when entry->non_unique_new_dir set */ if (!entry->non_unique_new_dir) - BUG("entry->non_unqiue_dir not set and !new_path"); + BUG("entry->non_unique_new_dir not set and !new_path"); output(opt, 1, _("CONFLICT (directory rename split): " "Unclear where to place %s because directory " "%s was renamed to multiple other directories, " @@ -3021,7 +3073,7 @@ static int read_oid_strbuf(struct merge_options *opt, void *buf; enum object_type type; unsigned long size; - buf = read_object_file(oid, &type, &size); + buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) return err(opt, _("cannot read object %s"), oid_to_hex(oid)); if (type != OBJ_BLOB) { @@ -3592,7 +3644,9 @@ static int merge_recursive_internal(struct merge_options *opt, } if (!merge_bases) { - merge_bases = get_merge_bases(h1, h2); + if (repo_get_merge_bases(the_repository, h1, h2, + &merge_bases) < 0) + return -1; merge_bases = reverse_commit_list(merge_bases); } @@ -3797,7 +3851,7 @@ static struct commit *get_ref(struct repository *repo, return make_virtual_commit(repo, (struct tree*)object, name); if (object->type != OBJ_COMMIT) return NULL; - if (parse_commit((struct commit *)object)) + if (repo_parse_commit(repo, (struct commit *)object)) return NULL; return (struct commit *)object; } @@ -3894,6 +3948,8 @@ void init_merge_options(struct merge_options *opt, opt->renormalize = 0; + opt->conflict_style = -1; + merge_recursive_config(opt); merge_verbosity = getenv("GIT_MERGE_VERBOSITY"); if (merge_verbosity) @@ -3902,6 +3958,22 @@ void init_merge_options(struct merge_options *opt, opt->buffer_output = 0; } +/* + * For now, members of merge_options do not need deep copying, but + * it may change in the future, in which case we would need to update + * this, and also make a matching change to clear_merge_options() to + * release the resources held by a copied instance. + */ +void copy_merge_options(struct merge_options *dst, struct merge_options *src) +{ + *dst = *src; +} + +void clear_merge_options(struct merge_options *opt UNUSED) +{ + ; /* no-op as our copy is shallow right now */ +} + int parse_merge_opt(struct merge_options *opt, const char *s) { const char *arg; |