#include "cache.h"
#include "tree-walk.h"
+#include "xdiff-interface.h"
#include "blob.h"
static const char merge_tree_usage[] = "git-merge-tree <base-tree> <branch1> <branch2>";
return "removed in remote";
}
+extern void *merge_file(struct blob *, struct blob *, struct blob *, unsigned long *);
+
+static void *result(struct merge_list *entry, unsigned long *size)
+{
+ enum object_type type;
+ struct blob *base, *our, *their;
+
+ if (!entry->stage)
+ return read_sha1_file(entry->blob->object.sha1, &type, size);
+ base = NULL;
+ if (entry->stage == 1) {
+ base = entry->blob;
+ entry = entry->link;
+ }
+ our = NULL;
+ if (entry && entry->stage == 2) {
+ our = entry->blob;
+ entry = entry->link;
+ }
+ their = NULL;
+ if (entry)
+ their = entry->blob;
+ return merge_file(base, our, their, size);
+}
+
+static void *origin(struct merge_list *entry, unsigned long *size)
+{
+ enum object_type type;
+ while (entry) {
+ if (entry->stage == 2)
+ return read_sha1_file(entry->blob->object.sha1, &type, size);
+ entry = entry->link;
+ }
+ return NULL;
+}
+
+static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf)
+{
+ int i;
+ for (i = 0; i < nbuf; i++)
+ printf("%.*s", (int) mb[i].size, mb[i].ptr);
+ return 0;
+}
+
+static void show_diff(struct merge_list *entry)
+{
+ unsigned long size;
+ mmfile_t src, dst;
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
+ xdemitcb_t ecb;
+
+ xpp.flags = XDF_NEED_MINIMAL;
+ xecfg.ctxlen = 3;
+ xecfg.flags = 0;
+ ecb.outf = show_outf;
+ ecb.priv = NULL;
+
+ src.ptr = origin(entry, &size);
+ if (!src.ptr)
+ size = 0;
+ src.size = size;
+ dst.ptr = result(entry, &size);
+ if (!dst.ptr)
+ size = 0;
+ dst.size = size;
+ xdl_diff(&src, &dst, &xpp, &xecfg, &ecb);
+ free(src.ptr);
+ free(dst.ptr);
+}
+
static void show_result_list(struct merge_list *entry)
{
printf("%s\n", explanation(entry));
walk = merge_result;
while (walk) {
show_result_list(walk);
+ show_diff(walk);
walk = walk->next;
}
}
{
return a->sha1 &&
b->sha1 &&
- !memcmp(a->sha1, b->sha1, 20) &&
+ !hashcmp(a->sha1, b->sha1) &&
a->mode == b->mode;
}
if (!branch1)
return;
- path = strdup(mkpath("%s%s", base, result->path));
+ path = xstrdup(mkpath("%s%s", base, result->path));
orig = create_entry(2, branch1->mode, branch1->sha1, path);
final = create_entry(0, result->mode, result->sha1, path);
static int unresolved_directory(const char *base, struct name_entry n[3])
{
- int baselen;
+ int baselen, pathlen;
char *newbase;
struct name_entry *p;
struct tree_desc t[3];
if (!S_ISDIR(p->mode))
return 0;
baselen = strlen(base);
- newbase = xmalloc(baselen + p->pathlen + 2);
+ pathlen = tree_entry_len(p->path, p->sha1);
+ newbase = xmalloc(baselen + pathlen + 2);
memcpy(newbase, base, baselen);
- memcpy(newbase + baselen, p->path, p->pathlen);
- memcpy(newbase + baselen + p->pathlen, "/", 2);
+ memcpy(newbase + baselen, p->path, pathlen);
+ memcpy(newbase + baselen + pathlen, "/", 2);
buf0 = fill_tree_descriptor(t+0, n[0].sha1);
buf1 = fill_tree_descriptor(t+1, n[1].sha1);
if (entry)
path = entry->path;
else
- path = strdup(mkpath("%s%s", base, n->path));
+ path = xstrdup(mkpath("%s%s", base, n->path));
link = create_entry(stage, n->mode, n->sha1, path);
link->link = entry;
return link;
struct tree_desc t[3];
void *buf1, *buf2, *buf3;
- if (argc < 4)
+ if (argc != 4)
usage(merge_tree_usage);
+ setup_git_directory();
+
buf1 = get_tree_descriptor(t+0, argv[1]);
buf2 = get_tree_descriptor(t+1, argv[2]);
buf3 = get_tree_descriptor(t+2, argv[3]);