static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error(_("Unable to write index.")); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean, x; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; struct commit_list *j; if (remoteheads->next) { error(_("Not handling anything other than two heads merge.")); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_shift = ""; o.renormalize = option_renormalize; o.show_rename_progress = show_progress == -1 ? isatty(2) : show_progress; for (x = 0; x < xopts_nr; x++) if (parse_merge_opt(&o, xopts[x])) die(_("Unknown option for merge-recursive: -X%s"), xopts[x]); o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die (_("unable to write %s"), get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { return try_merge_command(strategy, xopts_nr, xopts, common, head_arg, remoteheads); } }
int merge_recursive_generic(struct merge_options *o, const unsigned char *head, const unsigned char *merge, int num_base_list, const unsigned char **base_list, struct commit **result) { int clean, index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct commit *head_commit = get_ref(head, o->branch1); struct commit *next_commit = get_ref(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], sha1_to_hex(base_list[i])))) return error("Could not parse object '%s'", sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } } index_fd = hold_locked_index(lock, 1); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); return clean ? 0 : 1; }
static int real_merge (SeafRepo *repo, SeafCommit *head, CloneTask *task) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; char *root_id = NULL; int clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { seaf_warning ("Failed to load index.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = task->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = head->creator_name; opts.remote_head = head->commit_id; /* Don't need to check locked files on windows. */ opts.force_merge = TRUE; if (repo->encrypted) { opts.crypt = seafile_crypt_new (repo->enc_version, repo->enc_key, repo->enc_iv); } /* Merge the downloaded branch with the current worktree contents. * EMPTY_SHA1 represents an empty common ancestor tree. */ merge_recursive (&opts, task->root_id, head->root_id, EMPTY_SHA1, &clean, &root_id); g_free (root_id); if (update_index (&istate, index_path) < 0) { seaf_warning ("Failed to update index.\n"); return -1; } /* We only update the worktree and index, but don't commit. * The next auto-commit cycle will check and do that for us. */ discard_index (&istate); g_free (opts.crypt); clear_merge_options (&opts); return 0; }
void merge_sort(tour_t** tours, int a, int b) { if (b-a > 1) { // recursive step int middex = (a+b)/2; merge_sort(tours, a, middex); merge_sort(tours, middex+1, b); // return the recursive merge merge_recursive(tours,a,middex,b); } else { // base step if (tours[b]->fitness < tours[a]->fitness) merge_swap(&tours[a],&tours[b]); } }
/* * Get the new blocks that need to be checked out if we do a real merge. */ static int get_new_blocks_merge (SeafRepo *repo, SeafCommit *head, SeafCommit *remote, SeafCommit *common, BlockList **bl) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; int ret, clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("Failed to load index.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = repo->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = remote->creator_name; opts.collect_blocks_only = TRUE; *bl = block_list_new(); opts.bl = *bl; ret = merge_recursive (&opts, head->root_id, remote->root_id, common->root_id, &clean, NULL); clear_merge_options (&opts); discard_index (&istate); return ret; }
bool merge_recursive(ucl_object_t *top, ucl_object_t *elt, bool copy) { const ucl_object_t *cur; ucl_object_iter_t it = NULL; ucl_object_t *found = NULL, *cp_obj = NULL; bool success = false; it = ucl_object_iterate_new(elt); while ((cur = ucl_object_iterate_safe(it, false))) { cp_obj = ucl_object_ref(cur); if (debug > 0) { fprintf(stderr, "DEBUG: Looping over (elt)%s, found key: %s\n", ucl_object_key(top), ucl_object_key(cur)); } if (ucl_object_type(cur) == UCL_OBJECT) { found = __DECONST(ucl_object_t *, ucl_object_find_key(top, ucl_object_key(cur))); if (found == NULL) { /* new key not found in old object, insert it */ if (debug > 0) { fprintf(stderr, "DEBUG: unmatched key, inserting: %s into top\n", ucl_object_key(cur)); } success = ucl_object_insert_key_merged(top, cp_obj, ucl_object_key(cp_obj), 0, true); if (success == false) { return false; } continue; } if (debug > 0) { fprintf(stderr, "DEBUG: (obj) Found key %s in (top)%s too, merging...\n", ucl_object_key(found), ucl_object_key(top)); } success = merge_recursive(found, cp_obj, copy); if (success == false) { return false; } } else if (ucl_object_type(cur) == UCL_ARRAY) {
static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { const char **args; int i = 0, ret; struct commit_list *j; struct strbuf buf = STRBUF_INIT; int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; if (remoteheads->next) { error("Not handling anything other than two heads merge."); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_merge = 1; o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remoteheads; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remoteheads; j; j = j->next) free((void *)args[i++]); free(args); discard_cache(); if (read_cache() < 0) die("failed to read the cache"); return ret; } }
/* * Merge the commits h1 and h2, return the resulting virtual * commit object and a flag indicating the cleanness of the merge. */ int merge_recursive(struct merge_options *o, struct commit *h1, struct commit *h2, struct commit_list *ca, struct commit **result) { struct commit_list *iter; struct commit *merged_common_ancestors; struct tree *mrtree = mrtree; int clean; if (show(o, 4)) { output(o, 4, "Merging:"); output_commit_title(o, h1); output_commit_title(o, h2); } if (!ca) { ca = get_merge_bases(h1, h2, 1); ca = reverse_commit_list(ca); } if (show(o, 5)) { output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) output_commit_title(o, iter->item); } merged_common_ancestors = pop_commit(&ca); if (merged_common_ancestors == NULL) { /* if there is no common ancestor, make an empty tree */ struct tree *tree = xcalloc(1, sizeof(struct tree)); tree->object.parsed = 1; tree->object.type = OBJ_TREE; pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } for (iter = ca; iter; iter = iter->next) { const char *saved_b1, *saved_b2; o->call_depth++; /* * When the merge fails, the result contains files * with conflict markers. The cleanness flag is * ignored, it was never actually used, as result of * merge_trees has always overwritten it: the committed * "conflicts" were already resolved. */ discard_cache(); saved_b1 = o->branch1; saved_b2 = o->branch2; o->branch1 = "Temporary merge branch 1"; o->branch2 = "Temporary merge branch 2"; merge_recursive(o, merged_common_ancestors, iter->item, NULL, &merged_common_ancestors); o->branch1 = saved_b1; o->branch2 = saved_b2; o->call_depth--; if (!merged_common_ancestors) die("merge returned no commit"); } discard_cache(); if (!o->call_depth) read_cache(); clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, &mrtree); if (o->call_depth) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } flush_output(o); return clean; }
int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { static const char *bases[20]; static unsigned bases_count = 0; int i, clean; const char *branch1, *branch2; struct commit *result, *h1, *h2; struct commit_list *ca = NULL; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) subtree_merge = 1; } git_config(merge_config, NULL); if (getenv("GIT_MERGE_VERBOSITY")) verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (argc < 4) die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]); for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--")) break; if (bases_count < sizeof(bases)/sizeof(*bases)) bases[bases_count++] = argv[i]; } if (argc - i != 3) /* "--" "<head>" "<remote>" */ die("Not handling anything other than two heads merge."); if (verbosity >= 5) buffer_output = 0; branch1 = argv[++i]; branch2 = argv[++i]; h1 = get_ref(branch1); h2 = get_ref(branch2); branch1 = better_branch_name(branch1); branch2 = better_branch_name(branch2); if (show(3)) printf("Merging %s with %s\n", branch1, branch2); index_fd = hold_locked_index(lock, 1); for (i = 0; i < bases_count; i++) { struct commit *ancestor = get_ref(bases[i]); ca = commit_list_insert(ancestor, &ca); } clean = merge_recursive(h1, h2, branch1, branch2, ca, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); return clean ? 0: 1; }
static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; int i; char *oneline, *reencoded_message = NULL; const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); git_config(git_default_config); me = action == REVERT ? "revert" : "cherry-pick"; setenv(GIT_REFLOG_ACTION, me, 0); parse_args(argc, argv); /* this is copied from the shell script, but it's never triggered... */ if (action == REVERT && !no_replay) die("revert is incompatible with replay"); if (no_commit) { /* * We do not intend to commit immediately. We just want to * merge the differences in, so let's compute the tree * that represents the "current" state for merge-recursive * to work on. */ if (write_cache_as_tree(head, 0, NULL)) die ("Your index file is unmerged."); } else { if (get_sha1("HEAD", head)) die ("You do not have a valid HEAD"); if (read_cache() < 0) die("could not read the index"); if (index_is_dirty()) die ("Dirty index: cannot %s", me); discard_cache(); } if (!commit->parents) die ("Cannot %s a root commit", me); if (commit->parents->next) { /* Reverting or cherry-picking a merge commit */ int cnt; struct commit_list *p; if (!mainline) die("Commit %s is a merge but no -m option was given.", sha1_to_hex(commit->object.sha1)); for (cnt = 1, p = commit->parents; cnt != mainline && p; cnt++) p = p->next; if (cnt != mainline || !p) die("Commit %s does not have parent %d", sha1_to_hex(commit->object.sha1), mainline); parent = p->item; } else if (0 < mainline) die("Mainline was specified but commit %s is not a merge.", sha1_to_hex(commit->object.sha1)); else parent = commit->parents->item; if (!(message = commit->buffer)) die ("Cannot get commit message for %s", sha1_to_hex(commit->object.sha1)); /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" * on top of the current HEAD if we are cherry-pick. Or the * reverse of it if we are revert. */ msg_fd = hold_lock_file_for_update(&msg_file, defmsg, 1); encoding = get_encoding(message); if (!encoding) encoding = "utf-8"; if (!git_commit_encoding) git_commit_encoding = "utf-8"; if ((reencoded_message = reencode_string(message, git_commit_encoding, encoding))) message = reencoded_message; oneline = get_oneline(message); if (action == REVERT) { char *oneline_body = strchr(oneline, ' '); base = commit; next = parent; add_to_msg("Revert \""); add_to_msg(oneline_body + 1); add_to_msg("\"\n\nThis reverts commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); add_to_msg(".\n"); } else { base = parent; next = commit; set_author_ident_env(message); add_message_to_msg(message); if (no_replay) { add_to_msg("(cherry picked from commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); add_to_msg(")\n"); } } if (merge_recursive(sha1_to_hex(base->object.sha1), sha1_to_hex(head), "HEAD", sha1_to_hex(next->object.sha1), oneline) || write_cache_as_tree(head, 0, NULL)) { add_to_msg("\nConflicts:\n\n"); read_cache(); for (i = 0; i < active_nr;) { struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { add_to_msg("\t"); add_to_msg(ce->name); add_to_msg("\n"); while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)) i++; } } if (commit_lock_file(&msg_file) < 0) die ("Error wrapping up %s", defmsg); fprintf(stderr, "Automatic %s failed.%s\n", me, help_msg(commit->object.sha1)); exit(1); } if (commit_lock_file(&msg_file) < 0) die ("Error wrapping up %s", defmsg); fprintf(stderr, "Finished one %s.\n", me); /* * * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original * author date and name. * If we are revert, or if our cherry-pick results in a hand merge, * we had better say that the current user is responsible for that. */ if (!no_commit) { /* 6 is max possible length of our args array including NULL */ const char *args[6]; int i = 0; args[i++] = "commit"; args[i++] = "-n"; if (signoff) args[i++] = "-s"; if (!edit) { args[i++] = "-F"; args[i++] = defmsg; } args[i] = NULL; return execv_git_cmd(args); } free(reencoded_message); return 0; }
static int do_real_merge (SeafRepo *repo, SeafBranch *head_branch, SeafCommit *head, SeafBranch *remote_branch, SeafCommit *remote, SeafCommit *common, gboolean recover_merge, char **error) { struct merge_options opts; char index_path[SEAF_PATH_MAX]; struct index_state istate; char *root_id = NULL; SeafCommit *merged; int ret = 0, clean; memset (&istate, 0, sizeof(istate)); snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id); if (read_index_from (&istate, index_path) < 0) { g_warning ("Failed to load index.\n"); *error = g_strdup ("Internal error.\n"); return -1; } init_merge_options (&opts); opts.index = &istate; opts.worktree = repo->worktree; opts.ancestor = "common ancestor"; opts.branch1 = seaf->session->base.user_name; opts.branch2 = remote->creator_name; opts.remote_head = remote->commit_id; opts.recover_merge = recover_merge; if (repo->encrypted) { opts.crypt = seafile_crypt_new (repo->enc_version, repo->enc_key, repo->enc_iv); } ret = merge_recursive (&opts, head->root_id, remote->root_id, common->root_id, &clean, &root_id); if (ret < 0) goto out; if (update_index (&istate, index_path) < 0) { *error = g_strdup ("Internal error.\n"); ret = -1; goto out; } if (clean) { merged = seaf_commit_new (NULL, repo->id, root_id, repo->email ? repo->email : seaf->session->base.user_name, seaf->session->base.id, "Auto merge by seafile system", 0); merged->parent_id = g_strdup(head->commit_id); merged->second_parent_id = g_strdup(remote->commit_id); seaf_repo_to_commit (repo, merged); if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged) < 0) { seaf_commit_unref (merged); *error = g_strdup ("Internal error.\n"); ret = -1; goto out; } seaf_branch_set_commit (head_branch, merged->commit_id); seaf_branch_manager_update_branch (seaf->branch_mgr, head_branch); g_debug ("Auto merged.\n"); seaf_commit_unref (merged); } else { ret = -1; g_debug ("Auto merge failed.\n"); } out: if (root_id) g_free (root_id); g_free (opts.crypt); clear_merge_options (&opts); discard_index (&istate); return ret; }
int merge_mode(char *destination_node, char *data) { ucl_object_t *dst_obj = NULL; ucl_object_t *sub_obj = NULL; ucl_object_t *old_obj = NULL; ucl_object_t *tmp_obj = NULL; int success = 0; char *dst_frag; setparser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE | UCL_PARSER_NO_IMPLICIT_ARRAYS); /* Lookup the destination to write to */ dst_obj = get_parent(destination_node); sub_obj = get_object(destination_node); if (sub_obj == NULL) { fprintf(stderr, "Failed to find destination node: %s\n", destination_node); return false; } if (include_file != NULL) { /* get UCL to add from file */ set_obj = parse_file(setparser, include_file); } else if (data == NULL || strcmp(data, "-") == 0) { /* get UCL to add from stdin */ set_obj = parse_input(setparser, stdin); } else { /* User provided data inline */ set_obj = parse_string(setparser, data); } if (debug > 0) { char *rt = NULL, *dt = NULL, *st = NULL; rt = objtype_as_string(dst_obj); dt = objtype_as_string(sub_obj); st = objtype_as_string(set_obj); fprintf(stderr, "root type: %s, destination type: %s, new type: %s\n", rt, dt, st); if (rt != NULL) free(rt); if (dt != NULL) free(dt); if (st != NULL) free(st); fprintf(stderr, "Merging key %s to root: %s\n", ucl_object_key(sub_obj), ucl_object_key(dst_obj)); } dst_frag = strrchr(destination_node, input_sepchar); if (dst_frag == NULL) { dst_frag = destination_node; } else { dst_frag++; } /* Add it to the object here */ if (sub_obj == dst_obj && *dst_frag != '\0') { /* Sub-object does not exist, create a new one */ success = ucl_object_insert_key(dst_obj, set_obj, dst_frag, 0, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY && ucl_object_type(set_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Merging array of size %u with array of size %u\n", sub_obj->len, set_obj->len); } success = ucl_array_merge(sub_obj, set_obj, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Appending object to array of size %u\n", sub_obj->len); } success = ucl_array_append(sub_obj, ucl_object_ref(set_obj)); } else if (ucl_object_type(sub_obj) == UCL_OBJECT && ucl_object_type(set_obj) == UCL_OBJECT) { if (debug > 0) { fprintf(stderr, "Merging object %s with object %s\n", ucl_object_key(sub_obj), ucl_object_key(set_obj)); } /* XXX not supported: * success = ucl_object_merge(sub_obj, set_obj, false, true); */ /* Old non-recursive way */ /* success = ucl_object_merge(sub_obj, set_obj, false); */ success = merge_recursive(sub_obj, set_obj, false); } else if (ucl_object_type(sub_obj) != UCL_OBJECT && ucl_object_type(sub_obj) != UCL_ARRAY) { /* Create an explicit array */ if (debug > 0) { fprintf(stderr, "Creating an array and appended the new item\n"); } tmp_obj = ucl_object_typed_new(UCL_ARRAY); /* * Reference and Append the original scalar * The additional reference is required because the old object will be * unreferenced as part of the ucl_object_replace_key operation */ ucl_array_append(tmp_obj, ucl_object_ref(sub_obj)); /* Reference and Append the new scalar (unref in cleanup()) */ ucl_array_append(tmp_obj, ucl_object_ref(set_obj)); /* Replace the old object with the newly created one */ if (ucl_object_type(dst_obj) == UCL_ARRAY) { old_obj = ucl_array_replace_index(dst_obj, tmp_obj, ucl_array_index_of(dst_obj, sub_obj)); success = false; if (old_obj != NULL) { ucl_object_unref(old_obj); success = true; } } else { success = ucl_object_replace_key(dst_obj, tmp_obj, ucl_object_key(sub_obj), 0, true); } } else { if (debug > 0) { fprintf(stderr, "Merging object into key %s\n", ucl_object_key(sub_obj)); } success = ucl_object_insert_key_merged(dst_obj, ucl_object_ref(set_obj), ucl_object_key(sub_obj), 0, true); } return success; }