static int ll_merge_in_worktree(struct notes_merge_options *o, struct notes_merge_pair *p) { mmbuffer_t result_buf; mmfile_t base, local, remote; int status; read_mmblob(&base, p->base); read_mmblob(&local, p->local); read_mmblob(&remote, p->remote); status = ll_merge(&result_buf, sha1_to_hex(p->obj), &base, NULL, &local, o->local_ref, &remote, o->remote_ref, NULL); free(base.ptr); free(local.ptr); free(remote.ptr); if ((status < 0) || !result_buf.ptr) die("Failed to execute internal merge"); write_buf_to_worktree(p->obj, result_buf.ptr, result_buf.size); free(result_buf.ptr); return status; }
static int merge_3way(struct merge_options *o, mmbuffer_t *result_buf, struct diff_filespec *one, struct diff_filespec *a, struct diff_filespec *b, const char *branch1, const char *branch2) { mmfile_t orig, src1, src2; char *base_name, *name1, *name2; int merge_status; int favor; if (o->call_depth) favor = 0; else { switch (o->recursive_variant) { case MERGE_RECURSIVE_OURS: favor = XDL_MERGE_FAVOR_OURS; break; case MERGE_RECURSIVE_THEIRS: favor = XDL_MERGE_FAVOR_THEIRS; break; default: favor = 0; break; } } if (strcmp(a->path, b->path) || (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) { base_name = o->ancestor == NULL ? NULL : xstrdup(mkpath("%s:%s", o->ancestor, one->path)); name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); } else { base_name = o->ancestor == NULL ? NULL : xstrdup(mkpath("%s", o->ancestor)); name1 = xstrdup(mkpath("%s", branch1)); name2 = xstrdup(mkpath("%s", branch2)); } read_mmblob(&orig, one->sha1); read_mmblob(&src1, a->sha1); read_mmblob(&src2, b->sha1); merge_status = ll_merge(result_buf, a->path, &orig, base_name, &src1, name1, &src2, name2, (!!o->call_depth) | (favor << 1)); free(name1); free(name2); free(orig.ptr); free(src1.ptr); free(src2.ptr); return merge_status; }
static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts) { struct cache_entry *ce = active_cache[pos]; const char *path = ce->name; mmfile_t ancestor, ours, theirs; int status; struct object_id oid; mmbuffer_t result_buf; struct object_id threeway[3]; unsigned mode = 0; memset(threeway, 0, sizeof(threeway)); while (pos < active_nr) { int stage; stage = ce_stage(ce); if (!stage || strcmp(path, ce->name)) break; oidcpy(&threeway[stage - 1], &ce->oid); if (stage == 2) mode = create_ce_mode(ce->ce_mode); pos++; ce = active_cache[pos]; } if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2])) return error(_("path '%s' does not have necessary versions"), path); read_mmblob(&ancestor, &threeway[0]); read_mmblob(&ours, &threeway[1]); read_mmblob(&theirs, &threeway[2]); /* * NEEDSWORK: re-create conflicts from merges with * merge.renormalize set, too */ status = ll_merge(&result_buf, path, &ancestor, "base", &ours, "ours", &theirs, "theirs", state->istate, NULL); free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); if (status < 0 || !result_buf.ptr) { free(result_buf.ptr); return error(_("path '%s': cannot merge"), path); } /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object * and create a phony cache entry. This hack is primarily to get * to the write_entry() machinery that massages the contents to * work-tree format and writes out which only allows it for a * cache entry. The code in write_entry() needs to be refactored * to allow us to feed a <buffer, size, mode> instead of a cache * entry. Such a refactoring would help merge_recursive as well * (it also writes the merge result to the object database even * when it may contain conflicts). */ if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid)) die(_("Unable to add merge result for '%s'"), path); free(result_buf.ptr); ce = make_transient_cache_entry(mode, &oid, path, 2); if (!ce) die(_("make_cache_entry failed for path '%s'"), path); status = checkout_entry(ce, state, NULL, nr_checkouts); discard_cache_entry(ce); return status; }