{"thread":{"id":"14097","subject":"[PATCH 2/2] git-merge-recursive-{ours,theirs}","startedAt":"2008-06-23T12:45:26Z","lastAt":"2008-06-23T12:45:27Z","messageCount":2,"participants":["Miklos Vajna"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"80699","messageId":"cover.1214224424.git.vmiklos@frugalware.org","threadId":"14097","inReplyTo":null,"subject":"[PATCH 0/2] jc/merge-theirs, rebased on top of mv/merge-in-c","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-06-23T12:45:26Z","receivedAt":"2008-06-23T12:45:26Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jun 23, 2008 at 12:15:35AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Currently tip of 'pu' is broken and does not pass tests, as j6t/mingw\n> has interaction with dr/ceiling and jc/merge-theirs has interaction\n> with mv/merge-in-c.\n\nHere is jc/merge-theirs, on top of mv/merge-in-c. Now all tests pass\nhere if I merge both to master.\n\nTo avoid unnecessary traffic, I do not send e0aafb4 ([PATCH 1/2]\ngit-merge-file --ours, --theirs\"), as that is unchanged.\n\nJunio C Hamano (2):\n  git-merge-file --ours, --theirs\n  git-merge-recursive-{ours,theirs}\n\n Documentation/git-merge-file.txt |   12 +++++++-\n Makefile                         |    3 ++\n builtin-merge-file.c             |   10 +++++-\n builtin-merge-recursive.c        |   37 ++++++++++++++++++++++---\n builtin-merge.c                  |    2 +\n git.c                            |    2 +\n ll-merge.c                       |   24 ++++++++++------\n ll-merge.h                       |    4 ++-\n t/t6034-merge-ours-theirs.sh     |   56 ++++++++++++++++++++++++++++++++++++++\n xdiff/xdiff.h                    |    8 +++++-\n xdiff/xmerge.c                   |   24 +++++++++++-----\n 11 files changed, 155 insertions(+), 27 deletions(-)\n create mode 100755 t/t6034-merge-ours-theirs.sh\n"},{"id":"80698","messageId":"e0243ced5ebe387a18c33da236b7310b4e5d0e82.1214224424.git.vmiklos@frugalware.org","threadId":"14097","inReplyTo":"cover.1214224424.git.vmiklos@frugalware.org","subject":"[PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-06-23T12:45:27Z","receivedAt":"2008-06-23T12:45:27Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"From: Junio C Hamano <gitster@pobox.com>\n\nThis uses the low-level mechanism for \"ours\" and \"theirs\" autoresolution\nintroduced by the previous commit to introduce two additional merge\nstrategies, merge-recursive-ours and merge-recursive-theirs.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\nThe patch is the same, but I removed modifications to git-merge.sh and\nadded them to builtin-merge.c.\n\n Makefile                     |    3 ++\n builtin-merge-recursive.c    |   37 ++++++++++++++++++++++++---\n builtin-merge.c              |    2 +\n git.c                        |    2 +\n ll-merge.c                   |   24 +++++++++++------\n ll-merge.h                   |    4 ++-\n t/t6034-merge-ours-theirs.sh |   56 ++++++++++++++++++++++++++++++++++++++++++\n 7 files changed, 114 insertions(+), 14 deletions(-)\n create mode 100755 t/t6034-merge-ours-theirs.sh\n\ndiff --git a/Makefile b/Makefile\nindex 3d8c3d2..4e354fc 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -303,6 +303,8 @@ BUILT_INS += git-format-patch$X\n BUILT_INS += git-fsck-objects$X\n BUILT_INS += git-get-tar-commit-id$X\n BUILT_INS += git-init$X\n+BUILT_INS += git-merge-recursive-ours$X\n+BUILT_INS += git-merge-recursive-theirs$X\n BUILT_INS += git-merge-subtree$X\n BUILT_INS += git-peek-remote$X\n BUILT_INS += git-repo-config$X\n@@ -1381,6 +1383,7 @@ check-docs::\n \tdo \\\n \t\tcase \"$$v\" in \\\n \t\tgit-merge-octopus | git-merge-ours | git-merge-recursive | \\\n+\t\tgit-merge-recursive-ours | git-merge-recursive-theirs | \\\n \t\tgit-merge-resolve | git-merge-stupid | git-merge-subtree | \\\n \t\tgit-fsck-objects | git-init-db | \\\n \t\tgit-?*--?* ) continue ;; \\\ndiff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c\nindex 98b09fb..c535596 100644\n--- a/builtin-merge-recursive.c\n+++ b/builtin-merge-recursive.c\n@@ -20,7 +20,11 @@\n #include \"attr.h\"\n #include \"merge-recursive.h\"\n \n-static int subtree_merge;\n+static enum {\n+\tMERGE_RECURSIVE_SUBTREE = 1,\n+\tMERGE_RECURSIVE_OURS,\n+\tMERGE_RECURSIVE_THEIRS,\n+} merge_recursive_variants;\n \n static struct tree *shift_tree_object(struct tree *one, struct tree *two)\n {\n@@ -634,6 +638,7 @@ static int merge_3way(mmbuffer_t *result_buf,\n \tmmfile_t orig, src1, src2;\n \tchar *name1, *name2;\n \tint merge_status;\n+\tint flag, favor;\n \n \tname1 = xstrdup(mkpath(\"%s:%s\", branch1, a->path));\n \tname2 = xstrdup(mkpath(\"%s:%s\", branch2, b->path));\n@@ -642,9 +647,26 @@ static int merge_3way(mmbuffer_t *result_buf,\n \tfill_mm(a->sha1, &src1);\n \tfill_mm(b->sha1, &src2);\n \n+\tif (index_only)\n+\t\tfavor = 0;\n+\telse {\n+\t\tswitch (merge_recursive_variants) {\n+\t\tcase MERGE_RECURSIVE_OURS:\n+\t\t\tfavor = XDL_MERGE_FAVOR_OURS;\n+\t\t\tbreak;\n+\t\tcase MERGE_RECURSIVE_THEIRS:\n+\t\t\tfavor = XDL_MERGE_FAVOR_THEIRS;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tfavor = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tflag = LL_MERGE_FLAGS(index_only, favor);\n+\n \tmerge_status = ll_merge(result_buf, a->path, &orig,\n \t\t\t\t&src1, name1, &src2, name2,\n-\t\t\t\tindex_only);\n+\t\t\t\tflag);\n \n \tfree(name1);\n \tfree(name2);\n@@ -1163,7 +1185,7 @@ int merge_trees(struct tree *head,\n {\n \tint code, clean;\n \n-\tif (subtree_merge) {\n+\tif (merge_recursive_variants == MERGE_RECURSIVE_SUBTREE) {\n \t\tmerge = shift_tree_object(head, merge);\n \t\tcommon = shift_tree_object(head, common);\n \t}\n@@ -1371,11 +1393,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)\n \tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n \tint index_fd;\n \n+\tmerge_recursive_variants = 0;\n \tif (argv[0]) {\n \t\tint namelen = strlen(argv[0]);\n \t\tif (8 < namelen &&\n \t\t    !strcmp(argv[0] + namelen - 8, \"-subtree\"))\n-\t\t\tsubtree_merge = 1;\n+\t\t\tmerge_recursive_variants = MERGE_RECURSIVE_SUBTREE;\n+\t\telse if (5 < namelen &&\n+\t\t\t !strcmp(argv[0] + namelen - 5, \"-ours\"))\n+\t\t\tmerge_recursive_variants = MERGE_RECURSIVE_OURS;\n+\t\telse if (7 < namelen &&\n+\t\t\t !strcmp(argv[0] + namelen - 7, \"-theirs\"))\n+\t\t\tmerge_recursive_variants = MERGE_RECURSIVE_THEIRS;\n \t}\n \n \tgit_config(merge_config, NULL);\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex dadde80..b7b1b71 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -52,6 +52,8 @@ static struct path_list_item strategy_items[] = {\n \t{ \"stupid\",     (void *)0 },\n \t{ \"ours\",       (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },\n \t{ \"subtree\",    (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },\n+\t{ \"recursive-ours\", (void *)NO_TRIVIAL },\n+\t{ \"recursive-theirs\", (void *)NO_TRIVIAL },\n };\n static struct path_list strategies = { strategy_items,\n \tARRAY_SIZE(strategy_items), 0, 0 };\ndiff --git a/git.c b/git.c\nindex 770aadd..f2a8ce5 100644\n--- a/git.c\n+++ b/git.c\n@@ -276,6 +276,8 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"merge-file\", cmd_merge_file },\n \t\t{ \"merge-ours\", cmd_merge_ours, RUN_SETUP },\n \t\t{ \"merge-recursive\", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"merge-recursive-ours\", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"merge-recursive-theirs\", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"merge-subtree\", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"mv\", cmd_mv, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"name-rev\", cmd_name_rev, RUN_SETUP },\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 9837c84..c6a05bf 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -19,7 +19,7 @@ typedef int (*ll_merge_fn)(const struct ll_merge_driver *,\n \t\t\t   mmfile_t *orig,\n \t\t\t   mmfile_t *src1, const char *name1,\n \t\t\t   mmfile_t *src2, const char *name2,\n-\t\t\t   int virtual_ancestor);\n+\t\t\t   int flag);\n \n struct ll_merge_driver {\n \tconst char *name;\n@@ -39,13 +39,15 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t   mmfile_t *orig,\n \t\t\t   mmfile_t *src1, const char *name1,\n \t\t\t   mmfile_t *src2, const char *name2,\n-\t\t\t   int virtual_ancestor)\n+\t\t\t   int flag)\n {\n \t/*\n \t * The tentative merge result is \"ours\" for the final round,\n \t * or common ancestor for an internal merge.  Still return\n \t * \"conflicted merge\" status.\n \t */\n+\tint virtual_ancestor = flag & 01;\n+\n \tmmfile_t *stolen = virtual_ancestor ? orig : src1;\n \n \tresult->ptr = stolen->ptr;\n@@ -60,9 +62,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\tmmfile_t *orig,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n-\t\t\tint virtual_ancestor)\n+\t\t\tint flag)\n {\n \txpparam_t xpp;\n+\tint favor = ((flag)>>1) & 03;\n \n \tif (buffer_is_binary(orig->ptr, orig->size) ||\n \t    buffer_is_binary(src1->ptr, src1->size) ||\n@@ -73,14 +76,15 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t\t       path_unused,\n \t\t\t\t       orig, src1, name1,\n \t\t\t\t       src2, name2,\n-\t\t\t\t       virtual_ancestor);\n+\t\t\t\t       flag);\n \t}\n \n \tmemset(&xpp, 0, sizeof(xpp));\n \treturn xdl_merge(orig,\n \t\t\t src1, name1,\n \t\t\t src2, name2,\n-\t\t\t &xpp, XDL_MERGE_ZEALOUS,\n+\t\t\t &xpp,\n+\t\t\t XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, favor),\n \t\t\t result);\n }\n \n@@ -90,11 +94,12 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t  mmfile_t *orig,\n \t\t\t  mmfile_t *src1, const char *name1,\n \t\t\t  mmfile_t *src2, const char *name2,\n-\t\t\t  int virtual_ancestor)\n+\t\t\t  int flag)\n {\n \tchar *src, *dst;\n \tlong size;\n \tconst int marker_size = 7;\n+\tint virtual_ancestor = flag & 01;\n \n \tint status = ll_xdl_merge(drv_unused, result, path_unused,\n \t\t\t\t  orig, src1, NULL, src2, NULL,\n@@ -158,7 +163,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \t\t\tmmfile_t *orig,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n-\t\t\tint virtual_ancestor)\n+\t\t\tint flag)\n {\n \tchar temp[3][50];\n \tchar cmdbuf[2048];\n@@ -362,10 +367,11 @@ int ll_merge(mmbuffer_t *result_buf,\n \t     mmfile_t *ancestor,\n \t     mmfile_t *ours, const char *our_label,\n \t     mmfile_t *theirs, const char *their_label,\n-\t     int virtual_ancestor)\n+\t     int flag)\n {\n \tconst char *ll_driver_name;\n \tconst struct ll_merge_driver *driver;\n+\tint virtual_ancestor = flag & 01;\n \n \tll_driver_name = git_path_check_merge(path);\n \tdriver = find_ll_merge_driver(ll_driver_name);\n@@ -375,5 +381,5 @@ int ll_merge(mmbuffer_t *result_buf,\n \treturn driver->fn(driver, result_buf, path,\n \t\t\t  ancestor,\n \t\t\t  ours, our_label,\n-\t\t\t  theirs, their_label, virtual_ancestor);\n+\t\t\t  theirs, their_label, flag);\n }\ndiff --git a/ll-merge.h b/ll-merge.h\nindex 5388422..5daef58 100644\n--- a/ll-merge.h\n+++ b/ll-merge.h\n@@ -5,11 +5,13 @@\n #ifndef LL_MERGE_H\n #define LL_MERGE_H\n \n+#define LL_MERGE_FLAGS(virtual_ancestor,favor) ((!!(virtual_ancestor)) | ((favor)<<1))\n+\n int ll_merge(mmbuffer_t *result_buf,\n \t     const char *path,\n \t     mmfile_t *ancestor,\n \t     mmfile_t *ours, const char *our_label,\n \t     mmfile_t *theirs, const char *their_label,\n-\t     int virtual_ancestor);\n+\t     int flag);\n \n #endif\ndiff --git a/t/t6034-merge-ours-theirs.sh b/t/t6034-merge-ours-theirs.sh\nnew file mode 100755\nindex 0000000..56a9247\n--- /dev/null\n+++ b/t/t6034-merge-ours-theirs.sh\n@@ -0,0 +1,56 @@\n+#!/bin/sh\n+\n+test_description='Merge-recursive ours and theirs variants'\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\tfor i in 1 2 3 4 5 6 7 8 9\n+\tdo\n+\t\techo \"$i\"\n+\tdone >file &&\n+\tgit add file &&\n+\tcp file elif &&\n+\tgit commit -m initial &&\n+\n+\tsed -e \"s/1/one/\" -e \"s/9/nine/\" >file <elif &&\n+\tgit commit -a -m ours &&\n+\n+\tgit checkout -b side HEAD^ &&\n+\n+\tsed -e \"s/9/nueve/\" >file <elif &&\n+\tgit commit -a -m theirs &&\n+\n+\tgit checkout master^0\n+'\n+\n+test_expect_success 'plain recursive - should conflict' '\n+\tgit reset --hard master &&\n+\ttest_must_fail git merge -s recursive side &&\n+\tgrep nine file &&\n+\tgrep nueve file &&\n+\t! grep 9 file &&\n+\tgrep one file &&\n+\t! grep 1 file\n+'\n+\n+test_expect_success 'recursive favouring theirs' '\n+\tgit reset --hard master &&\n+\tgit merge -s recursive-theirs side &&\n+\t! grep nine file &&\n+\tgrep nueve file &&\n+\t! grep 9 file &&\n+\tgrep one file &&\n+\t! grep 1 file\n+'\n+\n+test_expect_success 'recursive favouring ours' '\n+\tgit reset --hard master &&\n+\tgit merge -s recursive-ours side &&\n+\tgrep nine file &&\n+\t! grep nueve file &&\n+\t! grep 9 file &&\n+\tgrep one file &&\n+\t! grep 1 file\n+'\n+\n+test_done\n-- \n1.5.6\n"}]}