diff options
Diffstat (limited to 'merge-recursive.c')
-rw-r--r-- | merge-recursive.c | 191 |
1 files changed, 103 insertions, 88 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index 59ba4b4a1a..4851825aeb 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -146,7 +146,8 @@ static int err(struct merge_options *o, const char *err, ...) return -1; } -static struct tree *shift_tree_object(struct tree *one, struct tree *two, +static struct tree *shift_tree_object(struct repository *repo, + struct tree *one, struct tree *two, const char *subtree_shift) { struct object_id shifted; @@ -159,12 +160,14 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two, } if (oideq(&two->object.oid, &shifted)) return two; - return lookup_tree(the_repository, &shifted); + return lookup_tree(repo, &shifted); } -static struct commit *make_virtual_commit(struct tree *tree, const char *comment) +static struct commit *make_virtual_commit(struct repository *repo, + struct tree *tree, + const char *comment) { - struct commit *commit = alloc_commit_node(the_repository); + struct commit *commit = alloc_commit_node(repo); set_merge_remote_desc(commit, comment, (struct object *)commit); commit->maybe_tree = tree; @@ -343,22 +346,24 @@ static int add_cacheinfo(struct merge_options *o, unsigned int mode, const struct object_id *oid, const char *path, int stage, int refresh, int options) { + struct index_state *istate = o->repo->index; struct cache_entry *ce; int ret; - ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0); + ce = make_cache_entry(istate, mode, oid ? oid : &null_oid, path, stage, 0); if (!ce) return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path); - ret = add_cache_entry(ce, options); + ret = add_index_entry(istate, ce, options); if (refresh) { struct cache_entry *nce; - nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING); + nce = refresh_cache_entry(istate, ce, + CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING); if (!nce) return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path); if (nce != ce) - ret = add_cache_entry(nce, options); + ret = add_index_entry(istate, nce, options); } return ret; } @@ -386,7 +391,7 @@ static int unpack_trees_start(struct merge_options *o, o->unpack_opts.merge = 1; o->unpack_opts.head_idx = 2; o->unpack_opts.fn = threeway_merge; - o->unpack_opts.src_index = &the_index; + o->unpack_opts.src_index = o->repo->index; o->unpack_opts.dst_index = &tmp_index; o->unpack_opts.aggressive = !merge_detect_rename(o); setup_unpack_trees_porcelain(&o->unpack_opts, "merge"); @@ -396,16 +401,16 @@ static int unpack_trees_start(struct merge_options *o, init_tree_desc_from_tree(t+2, merge); rc = unpack_trees(3, t, &o->unpack_opts); - cache_tree_free(&active_cache_tree); + cache_tree_free(&o->repo->index->cache_tree); /* - * Update the_index to match the new results, AFTER saving a copy + * Update o->repo->index to match the new results, AFTER saving a copy * in o->orig_index. Update src_index to point to the saved copy. * (verify_uptodate() checks src_index, and the original index is * the one that had the necessary modification timestamps.) */ - o->orig_index = the_index; - the_index = tmp_index; + o->orig_index = *o->repo->index; + *o->repo->index = tmp_index; o->unpack_opts.src_index = &o->orig_index; return rc; @@ -420,12 +425,13 @@ static void unpack_trees_finish(struct merge_options *o) struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; + struct index_state *istate = o->repo->index; - if (unmerged_cache()) { + if (unmerged_index(istate)) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + for (i = 0; i < istate->cache_nr; i++) { + const struct cache_entry *ce = istate->cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce), (int)ce_namelen(ce), ce->name); @@ -433,16 +439,16 @@ struct tree *write_tree_from_memory(struct merge_options *o) BUG("unmerged index entries in merge-recursive.c"); } - if (!active_cache_tree) - active_cache_tree = cache_tree(); + if (!istate->cache_tree) + istate->cache_tree = cache_tree(); - if (!cache_tree_fully_valid(active_cache_tree) && - cache_tree_update(&the_index, 0) < 0) { + if (!cache_tree_fully_valid(istate->cache_tree) && + cache_tree_update(istate, 0) < 0) { err(o, _("error building trees")); return NULL; } - result = lookup_tree(the_repository, &active_cache_tree->oid); + result = lookup_tree(o->repo, &istate->cache_tree->oid); return result; } @@ -513,17 +519,17 @@ static struct stage_data *insert_stage_data(const char *path, * Create a dictionary mapping file names to stage_data objects. The * dictionary contains one entry for every path with a non-zero stage entry. */ -static struct string_list *get_unmerged(void) +static struct string_list *get_unmerged(struct index_state *istate) { struct string_list *unmerged = xcalloc(1, sizeof(struct string_list)); int i; unmerged->strdup_strings = 1; - for (i = 0; i < active_nr; i++) { + for (i = 0; i < istate->cache_nr; i++) { struct string_list_item *item; struct stage_data *e; - const struct cache_entry *ce = active_cache[i]; + const struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) continue; @@ -683,7 +689,7 @@ static int update_stages(struct merge_options *opt, const char *path, int clear = 1; int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK; if (clear) - if (remove_file_from_cache(path)) + if (remove_file_from_index(opt->repo->index, path)) return -1; if (o) if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options)) @@ -718,13 +724,14 @@ static int remove_file(struct merge_options *o, int clean, int update_working_directory = !o->call_depth && !no_wd; if (update_cache) { - if (remove_file_from_cache(path)) + if (remove_file_from_index(o->repo->index, path)) return -1; } if (update_working_directory) { if (ignore_case) { struct cache_entry *ce; - ce = cache_file_exists(path, strlen(path), ignore_case); + ce = index_file_exists(o->repo->index, path, strlen(path), + ignore_case); if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name)) return 0; } @@ -774,7 +781,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char * * check the working directory. If empty_ok is non-zero, also return * 0 in the case where the working-tree dir exists but is empty. */ -static int dir_in_way(const char *path, int check_working_copy, int empty_ok) +static int dir_in_way(struct index_state *istate, const char *path, + int check_working_copy, int empty_ok) { int pos; struct strbuf dirpath = STRBUF_INIT; @@ -783,12 +791,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok) strbuf_addstr(&dirpath, path); strbuf_addch(&dirpath, '/'); - pos = cache_name_pos(dirpath.buf, dirpath.len); + pos = index_name_pos(istate, dirpath.buf, dirpath.len); if (pos < 0) pos = -1 - pos; - if (pos < active_nr && - !strncmp(dirpath.buf, active_cache[pos]->name, dirpath.len)) { + if (pos < istate->cache_nr && + !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) { strbuf_release(&dirpath); return 1; } @@ -831,8 +839,10 @@ static int was_tracked(struct merge_options *o, const char *path) return 0; } -static int would_lose_untracked(const char *path) +static int would_lose_untracked(struct merge_options *o, const char *path) { + struct index_state *istate = o->repo->index; + /* * This may look like it can be simplified to: * return !was_tracked(o, path) && file_exists(path) @@ -850,19 +860,19 @@ static int would_lose_untracked(const char *path) * update_file()/would_lose_untracked(); see every comment in this * file which mentions "update_stages". */ - int pos = cache_name_pos(path, strlen(path)); + int pos = index_name_pos(istate, path, strlen(path)); if (pos < 0) pos = -1 - pos; - while (pos < active_nr && - !strcmp(path, active_cache[pos]->name)) { + while (pos < istate->cache_nr && + !strcmp(path, istate->cache[pos]->name)) { /* * If stage #0, it is definitely tracked. * If it has stage #2 then it was tracked * before this merge started. All other * cases the path was not tracked. */ - switch (ce_stage(active_cache[pos])) { + switch (ce_stage(istate->cache[pos])) { case 0: case 2: return 0; @@ -922,7 +932,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) * Do not unlink a file in the work tree if we are not * tracking it. */ - if (would_lose_untracked(path)) + if (would_lose_untracked(o, path)) return err(o, _("refusing to lose untracked file at '%s'"), path); @@ -972,7 +982,7 @@ static int update_file_flags(struct merge_options *o, } if (S_ISREG(mode)) { struct strbuf strbuf = STRBUF_INIT; - if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) { + if (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) { free(buf); size = strbuf.len; buf = strbuf_detach(&strbuf, NULL); @@ -1092,7 +1102,7 @@ static int merge_3way(struct merge_options *o, merge_status = ll_merge(result_buf, a->path, &orig, base_name, &src1, name1, &src2, name2, - &the_index, &ll_opts); + o->repo->index, &ll_opts); free(base_name); free(name1); @@ -1103,7 +1113,8 @@ static int merge_3way(struct merge_options *o, return merge_status; } -static int find_first_merges(struct object_array *result, const char *path, +static int find_first_merges(struct repository *repo, + struct object_array *result, const char *path, struct commit *a, struct commit *b) { int i, j; @@ -1123,7 +1134,7 @@ static int find_first_merges(struct object_array *result, const char *path, /* get all revisions that merge commit a */ xsnprintf(merged_revision, sizeof(merged_revision), "^%s", oid_to_hex(&a->object.oid)); - repo_init_revisions(the_repository, &revs, NULL); + repo_init_revisions(repo, &revs, NULL); rev_opts.submodule = path; /* FIXME: can't handle linked worktrees in submodules yet */ revs.single_worktree = path != NULL; @@ -1201,9 +1212,9 @@ static int merge_submodule(struct merge_options *o, return 0; } - if (!(commit_base = lookup_commit_reference(the_repository, base)) || - !(commit_a = lookup_commit_reference(the_repository, a)) || - !(commit_b = lookup_commit_reference(the_repository, b))) { + if (!(commit_base = lookup_commit_reference(o->repo, base)) || + !(commit_a = lookup_commit_reference(o->repo, a)) || + !(commit_b = lookup_commit_reference(o->repo, b))) { output(o, 1, _("Failed to merge submodule %s (commits not present)"), path); return 0; } @@ -1253,7 +1264,8 @@ static int merge_submodule(struct merge_options *o, return 0; /* find commit which merges them */ - parent_count = find_first_merges(&merges, path, commit_a, commit_b); + parent_count = find_first_merges(o->repo, &merges, path, + commit_a, commit_b); switch (parent_count) { case 0: output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path); @@ -1401,7 +1413,7 @@ static int handle_rename_via_dir(struct merge_options *o, */ const struct diff_filespec *dest = pair->two; - if (!o->call_depth && would_lose_untracked(dest->path)) { + if (!o->call_depth && would_lose_untracked(o, dest->path)) { char *alt_path = unique_path(o, dest->path, rename_branch); output(o, 1, _("Error: Refusing to lose untracked file at %s; " @@ -1439,8 +1451,8 @@ static int handle_change_delete(struct merge_options *o, const char *update_path = path; int ret = 0; - if (dir_in_way(path, !o->call_depth, 0) || - (!o->call_depth && would_lose_untracked(path))) { + if (dir_in_way(o->repo->index, path, !o->call_depth, 0) || + (!o->call_depth && would_lose_untracked(o, path))) { update_path = alt_path = unique_path(o, path, change_branch); } @@ -1450,7 +1462,7 @@ static int handle_change_delete(struct merge_options *o, * correct; since there is no true "middle point" between * them, simply reuse the base version for virtual merge base. */ - ret = remove_file_from_cache(path); + ret = remove_file_from_index(o->repo->index, path); if (!ret) ret = update_file(o, 0, o_oid, o_mode, update_path); } else { @@ -1526,7 +1538,7 @@ static int handle_rename_delete(struct merge_options *o, return -1; if (o->call_depth) - return remove_file_from_cache(dest->path); + return remove_file_from_index(o->repo->index, dest->path); else return update_stages(o, dest->path, NULL, rename_branch == o->branch1 ? dest : NULL, @@ -1607,10 +1619,10 @@ static int handle_file_collision(struct merge_options *o, /* Remove rename sources if rename/add or rename/rename(2to1) */ if (prev_path1) remove_file(o, 1, prev_path1, - o->call_depth || would_lose_untracked(prev_path1)); + o->call_depth || would_lose_untracked(o, prev_path1)); if (prev_path2) remove_file(o, 1, prev_path2, - o->call_depth || would_lose_untracked(prev_path2)); + o->call_depth || would_lose_untracked(o, prev_path2)); /* * Remove the collision path, if it wouldn't cause dirty contents @@ -1621,7 +1633,7 @@ static int handle_file_collision(struct merge_options *o, output(o, 1, _("Refusing to lose dirty file at %s"), collide_path); update_path = alt_path = unique_path(o, collide_path, "merged"); - } else if (would_lose_untracked(collide_path)) { + } else if (would_lose_untracked(o, collide_path)) { /* * Only way we get here is if both renames were from * a directory rename AND user had an untracked file @@ -1717,12 +1729,12 @@ static char *find_path_for_conflict(struct merge_options *o, const char *branch2) { char *new_path = NULL; - if (dir_in_way(path, !o->call_depth, 0)) { + if (dir_in_way(o->repo->index, path, !o->call_depth, 0)) { new_path = unique_path(o, path, branch1); output(o, 1, _("%s is a directory in %s adding " "as %s instead"), path, branch2, new_path); - } else if (would_lose_untracked(path)) { + } else if (would_lose_untracked(o, path)) { new_path = unique_path(o, path, branch1); output(o, 1, _("Refusing to lose untracked file" " at %s; adding as %s instead"), @@ -1783,14 +1795,14 @@ static int handle_rename_rename_1to2(struct merge_options *o, return -1; } else - remove_file_from_cache(a->path); + remove_file_from_index(o->repo->index, a->path); add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1); if (add) { if (update_file(o, 0, &add->oid, add->mode, b->path)) return -1; } else - remove_file_from_cache(b->path); + remove_file_from_index(o->repo->index, b->path); } else { /* * For each destination path, we need to see if there is a @@ -1887,7 +1899,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o, struct diff_queue_struct *ret; struct diff_options opts; - repo_diff_setup(the_repository, &opts); + repo_diff_setup(o->repo, &opts); opts.flags.recursive = 1; opts.flags.rename_empty = 0; opts.detect_rename = merge_detect_rename(o); @@ -3042,8 +3054,8 @@ static int blob_unchanged(struct merge_options *opt, * performed. Comparison can be skipped if both files are * unchanged since their sha1s have already been compared. */ - if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) | - renormalize_buffer(&the_index, path, a.buf, a.len, &a)) + if (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) | + renormalize_buffer(opt->repo->index, path, a.buf, a.len, &a)) ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len)); error_return: @@ -3124,7 +3136,7 @@ static int handle_content_merge(struct merge_options *o, a.path = (char *)path1; b.path = (char *)path2; - if (dir_in_way(path, !o->call_depth, + if (dir_in_way(o->repo->index, path, !o->call_depth, S_ISGITLINK(pair1->two->mode))) df_conflict_remains = 1; } @@ -3158,8 +3170,8 @@ static int handle_content_merge(struct merge_options *o, pos = index_name_pos(&o->orig_index, path, strlen(path)); ce = o->orig_index.cache[pos]; if (ce_skip_worktree(ce)) { - pos = index_name_pos(&the_index, path, strlen(path)); - ce = the_index.cache[pos]; + pos = index_name_pos(o->repo->index, path, strlen(path)); + ce = o->repo->index->cache[pos]; ce->ce_flags |= CE_SKIP_WORKTREE; } return mfi.clean; @@ -3178,7 +3190,7 @@ static int handle_content_merge(struct merge_options *o, if (df_conflict_remains || is_dirty) { char *new_path; if (o->call_depth) { - remove_file_from_cache(path); + remove_file_from_index(o->repo->index, path); } else { if (!mfi.clean) { if (update_stages(o, path, &one, &a, &b)) @@ -3338,7 +3350,7 @@ static int process_entry(struct merge_options *o, oid = b_oid; conf = _("directory/file"); } - if (dir_in_way(path, + if (dir_in_way(o->repo->index, path, !o->call_depth && !S_ISGITLINK(a_mode), 0)) { char *new_path = unique_path(o, path, add_branch); @@ -3349,7 +3361,7 @@ static int process_entry(struct merge_options *o, if (update_file(o, 0, oid, mode, new_path)) clean_merge = -1; else if (o->call_depth) - remove_file_from_cache(path); + remove_file_from_index(o->repo->index, path); free(new_path); } else { output(o, 2, _("Adding %s"), path); @@ -3397,18 +3409,19 @@ int merge_trees(struct merge_options *o, struct tree *common, struct tree **result) { + struct index_state *istate = o->repo->index; int code, clean; struct strbuf sb = STRBUF_INIT; - if (!o->call_depth && index_has_changes(&the_index, head, &sb)) { + if (!o->call_depth && repo_index_has_changes(o->repo, head, &sb)) { err(o, _("Your local changes to the following files would be overwritten by merge:\n %s"), sb.buf); return -1; } if (o->subtree_shift) { - merge = shift_tree_object(head, merge, o->subtree_shift); - common = shift_tree_object(head, common, o->subtree_shift); + merge = shift_tree_object(o->repo, head, merge, o->subtree_shift); + common = shift_tree_object(o->repo, head, common, o->subtree_shift); } if (oid_eq(&common->object.oid, &merge->object.oid)) { @@ -3428,7 +3441,7 @@ int merge_trees(struct merge_options *o, return -1; } - if (unmerged_cache()) { + if (unmerged_index(istate)) { struct string_list *entries; struct rename_info re_info; int i; @@ -3443,7 +3456,7 @@ int merge_trees(struct merge_options *o, get_files_dirs(o, head); get_files_dirs(o, merge); - entries = get_unmerged(); + entries = get_unmerged(o->repo->index); clean = detect_and_process_renames(o, common, head, merge, entries, &re_info); record_df_conflict_files(o, entries); @@ -3544,8 +3557,8 @@ int merge_recursive(struct merge_options *o, /* if there is no common ancestor, use an empty tree */ struct tree *tree; - tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree); - merged_common_ancestors = make_virtual_commit(tree, "ancestor"); + tree = lookup_tree(o->repo, o->repo->hash_algo->empty_tree); + merged_common_ancestors = make_virtual_commit(o->repo, tree, "ancestor"); } for (iter = ca; iter; iter = iter->next) { @@ -3559,7 +3572,7 @@ int merge_recursive(struct merge_options *o, * overwritten it: the committed "conflicts" were * already resolved. */ - discard_cache(); + discard_index(o->repo->index); saved_b1 = o->branch1; saved_b2 = o->branch2; o->branch1 = "Temporary merge branch 1"; @@ -3575,9 +3588,9 @@ int merge_recursive(struct merge_options *o, return err(o, _("merge returned no commit")); } - discard_cache(); + discard_index(o->repo->index); if (!o->call_depth) - read_cache(); + repo_read_index(o->repo); o->ancestor = "merged common ancestors"; clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2), @@ -3589,7 +3602,7 @@ int merge_recursive(struct merge_options *o, } if (o->call_depth) { - *result = make_virtual_commit(mrtree, "merged tree"); + *result = make_virtual_commit(o->repo, mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } @@ -3602,17 +3615,17 @@ int merge_recursive(struct merge_options *o, return clean; } -static struct commit *get_ref(const struct object_id *oid, const char *name) +static struct commit *get_ref(struct repository *repo, const struct object_id *oid, + const char *name) { struct object *object; - object = deref_tag(the_repository, parse_object(the_repository, oid), - name, - strlen(name)); + object = deref_tag(repo, parse_object(repo, oid), + name, strlen(name)); if (!object) return NULL; if (object->type == OBJ_TREE) - return make_virtual_commit((struct tree*)object, name); + return make_virtual_commit(repo, (struct tree*)object, name); if (object->type != OBJ_COMMIT) return NULL; if (parse_commit((struct commit *)object)) @@ -3629,22 +3642,22 @@ int merge_recursive_generic(struct merge_options *o, { int clean; struct lock_file lock = LOCK_INIT; - struct commit *head_commit = get_ref(head, o->branch1); - struct commit *next_commit = get_ref(merge, o->branch2); + struct commit *head_commit = get_ref(o->repo, head, o->branch1); + struct commit *next_commit = get_ref(o->repo, merge, o->branch2); struct commit_list *ca = NULL; if (base_list) { int i; for (i = 0; i < num_base_list; ++i) { struct commit *base; - if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i])))) + if (!(base = get_ref(o->repo, base_list[i], oid_to_hex(base_list[i])))) return err(o, _("Could not parse object '%s'"), oid_to_hex(base_list[i])); commit_list_insert(base, &ca); } } - hold_locked_index(&lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (clean < 0) { @@ -3652,7 +3665,7 @@ int merge_recursive_generic(struct merge_options *o, return clean; } - if (write_locked_index(&the_index, &lock, + if (write_locked_index(o->repo->index, &lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) return err(o, _("Unable to write index.")); @@ -3676,10 +3689,12 @@ static void merge_recursive_config(struct merge_options *o) git_config(git_xmerge_config, NULL); } -void init_merge_options(struct merge_options *o) +void init_merge_options(struct merge_options *o, + struct repository *repo) { const char *merge_verbosity; memset(o, 0, sizeof(struct merge_options)); + o->repo = repo; o->verbosity = 2; o->buffer_output = 1; o->diff_rename_limit = -1; |