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 *name1, *name2; int merge_status; name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); fill_mm(one->sha1, &orig); fill_mm(a->sha1, &src1); fill_mm(b->sha1, &src2); merge_status = ll_merge(result_buf, a->path, &orig, &src1, name1, &src2, name2, o->call_depth); free(name1); free(name2); free(orig.ptr); free(src1.ptr); free(src2.ptr); return merge_status; }
static int merge(const char *name, const char *path) { int ret; mmfile_t cur, base, other; mmbuffer_t result = {NULL, 0}; if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0) return 1; if (read_mmfile(&cur, rerere_path(name, "thisimage")) || read_mmfile(&base, rerere_path(name, "preimage")) || read_mmfile(&other, rerere_path(name, "postimage"))) return 1; ret = ll_merge(&result, path, &base, &cur, "", &other, "", 0); if (!ret) { FILE *f = fopen(path, "w"); if (!f) return error("Could not open %s: %s", path, strerror(errno)); if (fwrite(result.ptr, result.size, 1, f) != 1) error("Could not write %s: %s", path, strerror(errno)); if (fclose(f)) return error("Writing %s failed: %s", path, strerror(errno)); } free(cur.ptr); free(base.ptr); free(other.ptr); free(result.ptr); return ret; }
/* * Find the conflict identified by "id"; the change between its * "preimage" (i.e. a previous contents with conflict markers) and its * "postimage" (i.e. the corresponding contents with conflicts * resolved) may apply cleanly to the contents stored in "path", i.e. * the conflict this time around. * * Returns 0 for successful replay of recorded resolution, or non-zero * for failure. */ static int merge(const struct rerere_id *id, const char *path) { FILE *f; int ret; mmfile_t cur = {NULL, 0}, base = {NULL, 0}, other = {NULL, 0}; mmbuffer_t result = {NULL, 0}; /* * Normalize the conflicts in path and write it out to * "thisimage" temporary file. */ if (handle_file(path, NULL, rerere_path(id, "thisimage")) < 0) { ret = 1; goto out; } if (read_mmfile(&cur, rerere_path(id, "thisimage")) || read_mmfile(&base, rerere_path(id, "preimage")) || read_mmfile(&other, rerere_path(id, "postimage"))) { ret = 1; goto out; } /* * A three-way merge. Note that this honors user-customizable * low-level merge driver settings. */ ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", NULL); if (ret) goto out; /* * A successful replay of recorded resolution. * Mark that "postimage" was used to help gc. */ if (utime(rerere_path(id, "postimage"), NULL) < 0) warning("failed utime() on %s: %s", rerere_path(id, "postimage"), strerror(errno)); /* Update "path" with the resolution */ f = fopen(path, "w"); if (!f) return error("Could not open %s: %s", path, strerror(errno)); if (fwrite(result.ptr, result.size, 1, f) != 1) error("Could not write %s: %s", path, strerror(errno)); if (fclose(f)) return error("Writing %s failed: %s", path, strerror(errno)); out: free(cur.ptr); free(base.ptr); free(other.ptr); free(result.ptr); return ret; }
static int handle_cache(const char *path, unsigned char *sha1, const char *output) { mmfile_t mmfile[3]; mmbuffer_t result = {NULL, 0}; struct cache_entry *ce; int pos, len, i, hunk_no; struct rerere_io_mem io; int marker_size = ll_merge_marker_size(path); /* * Reproduce the conflicted merge in-core */ len = strlen(path); pos = cache_name_pos(path, len); if (0 <= pos) return -1; pos = -pos - 1; for (i = 0; i < 3; i++) { enum object_type type; unsigned long size; mmfile[i].size = 0; mmfile[i].ptr = NULL; if (active_nr <= pos) break; ce = active_cache[pos++]; if (ce_namelen(ce) != len || memcmp(ce->name, path, len) || ce_stage(ce) != i + 1) break; mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size); mmfile[i].size = size; } for (i = 0; i < 3; i++) { if (!mmfile[i].ptr && !mmfile[i].size) mmfile[i].ptr = xstrdup(""); } ll_merge(&result, path, &mmfile[0], &mmfile[1], "ours", &mmfile[2], "theirs", 0); for (i = 0; i < 3; i++) free(mmfile[i].ptr); memset(&io, 0, sizeof(io)); io.io.getline = rerere_mem_getline; if (output) io.io.output = fopen(output, "w"); else io.io.output = NULL; strbuf_init(&io.input, 0); strbuf_attach(&io.input, result.ptr, result.size, result.size); hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); strbuf_release(&io.input); if (io.io.output) fclose(io.io.output); return hunk_no; }
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 void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size) { int merge_status; mmbuffer_t res; /* * This function is only used by cmd_merge_tree, which * does not respect the merge.conflictstyle option. * There is no need to worry about a label for the * common ancestor. */ merge_status = ll_merge(&res, path, base, NULL, our, ".our", their, ".their", NULL); if (merge_status < 0) return NULL; *size = res.size; return res.ptr; }
/* * Try using the given conflict resolution "ID" to see * if that recorded conflict resolves cleanly what we * got in the "cur". */ static int try_merge(const struct rerere_id *id, const char *path, mmfile_t *cur, mmbuffer_t *result) { int ret; mmfile_t base = {NULL, 0}, other = {NULL, 0}; if (read_mmfile(&base, rerere_path(id, "preimage")) || read_mmfile(&other, rerere_path(id, "postimage"))) ret = 1; else /* * A three-way merge. Note that this honors user-customizable * low-level merge driver settings. */ ret = ll_merge(result, path, &base, NULL, cur, "", &other, "", NULL); free(base.ptr); free(other.ptr); return ret; }
/* Read control lines. In LapLink mode, OR the control lines with the * data lines to which they are connected. Not all drivers implement * reading the data lines, so be prepared for the ll_irecv() to fail. */ ll_error_t ll_rctl_wait(LL_PDEV self, unsigned *value) { unsigned char data = 0; ll_error_t err; err = ll_irctl_wait(self,value); if (err) return err; switch(self->lld_cable) { case LL_CABLE_LAPLINK: err = ll_irecv_poll(self, &data); if (err != LL_E_OK && err != LL_E_NOTIMPL) return err; if (err == LL_E_OK) ll_merge(value, data); break; case LL_CABLE_NORMAL: break; } return LL_E_OK; }
static int handle_cache(const char *path, unsigned char *sha1, const char *output) { mmfile_t mmfile[3] = {{NULL}}; mmbuffer_t result = {NULL, 0}; const struct cache_entry *ce; int pos, len, i, has_conflicts; struct rerere_io_mem io; int marker_size = ll_merge_marker_size(path); /* * Reproduce the conflicted merge in-core */ len = strlen(path); pos = cache_name_pos(path, len); if (0 <= pos) return -1; pos = -pos - 1; while (pos < active_nr) { enum object_type type; unsigned long size; ce = active_cache[pos++]; if (ce_namelen(ce) != len || memcmp(ce->name, path, len)) break; i = ce_stage(ce) - 1; if (!mmfile[i].ptr) { mmfile[i].ptr = read_object_file(&ce->oid, &type, &size); mmfile[i].size = size; } } for (i = 0; i < 3; i++) if (!mmfile[i].ptr && !mmfile[i].size) mmfile[i].ptr = xstrdup(""); /* * NEEDSWORK: handle conflicts from merges with * merge.renormalize set, too? */ ll_merge(&result, path, &mmfile[0], NULL, &mmfile[1], "ours", &mmfile[2], "theirs", NULL); for (i = 0; i < 3; i++) free(mmfile[i].ptr); memset(&io, 0, sizeof(io)); io.io.getline = rerere_mem_getline; if (output) io.io.output = fopen(output, "w"); else io.io.output = NULL; strbuf_init(&io.input, 0); strbuf_attach(&io.input, result.ptr, result.size, result.size); /* * Grab the conflict ID and optionally write the original * contents with conflict markers out. */ has_conflicts = handle_path(sha1, (struct rerere_io *)&io, marker_size); strbuf_release(&io.input); if (io.io.output) fclose(io.io.output); return has_conflicts; }
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; }