From 0c7993839b92f466278439a724023f8be50391c1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 28 Jun 2006 22:06:36 -0700 Subject: 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 Signed-off-by: Junio C Hamano --- merge-tree.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'merge-tree.c') 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 "; @@ -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; } } -- cgit v1.2.1