aboutsummaryrefslogtreecommitdiff
path: root/merge-tree.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@osdl.org>2006-06-28 22:06:36 -0700
committerJunio C Hamano <junkio@cox.net>2006-06-28 22:24:45 -0700
commit0c7993839b92f466278439a724023f8be50391c1 (patch)
treefd1fc5395f2dce9c742b0902c82fe60e4b9da718 /merge-tree.c
parent83788070a3dd0a4905dd76c865320c51f7d74a83 (diff)
downloadgit-0c7993839b92f466278439a724023f8be50391c1.tar.gz
git-0c7993839b92f466278439a724023f8be50391c1.tar.xz
Improved three-way blob merging code
This fleshes out the code that generates a three-way merge of a set of blobs. It still actually does the three-way merge using an external executable (ie just calling "merge"), but the interfaces have been cleaned up a lot and are now fully based on the 'mmfile_t' interface, so if libxdiff were to ever grow a compatible three-way-merge, it could probably be directly plugged in. It also uses the previous XDL_EMIT_COMMON functionality extension to libxdiff to generate a made-up base file for the merge for the case where no base file previously existed. This should be equivalent to what we currently do in git-merge-one-file.sh: diff -u -La/$orig -Lb/$orig $orig $src2 | git-apply --no-add except it should be much simpler and can be done using the direct libxdiff interfaces. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'merge-tree.c')
-rw-r--r--merge-tree.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/merge-tree.c b/merge-tree.c
index fd0c2111c..7cf00be6d 100644
--- a/merge-tree.c
+++ b/merge-tree.c
@@ -1,5 +1,6 @@
#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>";
@@ -52,6 +53,77 @@ static const char *explanation(struct merge_list *entry)
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)
+{
+ char type[20];
+ 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)
+{
+ char type[20];
+ 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));
@@ -70,6 +142,7 @@ static void show_result(void)
walk = merge_result;
while (walk) {
show_result_list(walk);
+ show_diff(walk);
walk = walk->next;
}
}