diff options
author | Linus Torvalds <torvalds@osdl.org> | 2006-06-28 22:06:36 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-06-28 22:24:45 -0700 |
commit | 0c7993839b92f466278439a724023f8be50391c1 (patch) | |
tree | fd1fc5395f2dce9c742b0902c82fe60e4b9da718 /merge-tree.c | |
parent | 83788070a3dd0a4905dd76c865320c51f7d74a83 (diff) | |
download | git-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.c | 73 |
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; } } |