{"thread":{"id":"13974","subject":"Guided merge with override","startedAt":"2008-06-16T04:16:38Z","lastAt":"2008-06-21T16:56:45Z","messageCount":22,"participants":["Geoff Russell","Miklos Vajna","Johannes Sixt","Sverre Rabbelier","Johannes Schindelin","Junio C Hamano","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"80003","messageId":"93c3eada0806152116v2cef4035u272dc1a26005661a@mail.gmail.com","threadId":"13974","inReplyTo":null,"subject":"Guided merge with override","fromName":"Geoff Russell","fromEmail":"geoffrey.russell@gmail.com","sentAt":"2008-06-16T04:16:38Z","receivedAt":"2008-06-16T04:16:38Z","isPatch":false,"sender":{"key":"geoffrey.russell@gmail.com","avatar":"https://gravatar.com/avatar/c30f497ccfa6bf06d86f30bd2ba092a2dd124c61c6bc902f7cb5c3f6486947de?d=mp&s=160"},"body":"I have a two repositories A and B.  B is a tiny subset of the files in\nA and all have been\nmodified.   If I do a \"git pull B\" into A, I get conflicts. I always\nwant to resolve these\nby accepting the version from B. Is there a magic \"override\" switch to\nlet me do this?\n\nCheers,\nGeoff Russell\n"},{"id":"80009","messageId":"20080616092554.GB29404@genesis.frugalware.org","threadId":"13974","inReplyTo":"93c3eada0806152116v2cef4035u272dc1a26005661a@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-06-16T09:25:54Z","receivedAt":"2008-06-16T09:25:54Z","isPatch":false,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jun 16, 2008 at 01:46:38PM +0930, Geoff Russell <geoffrey.russell@gmail.com> wrote:\n> I have a two repositories A and B.  B is a tiny subset of the files in\n> A and all have been\n> modified.   If I do a \"git pull B\" into A, I get conflicts. I always\n> want to resolve these\n> by accepting the version from B. Is there a magic \"override\" switch to\n> let me do this?\n\nThere was a thread about this:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/84047\n\nand then you can do a git pull -s theirs B.\n"},{"id":"80012","messageId":"48563D6C.8060704@viscovery.net","threadId":"13974","inReplyTo":"20080616092554.GB29404@genesis.frugalware.org","subject":"Re: Guided merge with override","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-06-16T10:16:12Z","receivedAt":"2008-06-16T10:16:12Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Miklos Vajna schrieb:\n> On Mon, Jun 16, 2008 at 01:46:38PM +0930, Geoff Russell <geoffrey.russell@gmail.com> wrote:\n>> I have a two repositories A and B.  B is a tiny subset of the files in\n>> A and all have been\n>> modified.   If I do a \"git pull B\" into A, I get conflicts. I always\n>> want to resolve these\n>> by accepting the version from B. Is there a magic \"override\" switch to\n>> let me do this?\n> \n> There was a thread about this:\n> \n> http://thread.gmane.org/gmane.comp.version-control.git/84047\n> \n> and then you can do a git pull -s theirs B.\n\nI don't think that's what Geoff needs. The 'theirs' strategy replaces the\nentire tree by 'their' - B's - tree. But IIUC, only the subset of files\nthat are contained in B should be replaced by B's version, the rest of the\nfiles should remain unchanged. This is quite different from 'theirs' strategy.\n\nThe solution depends on whether *all* files in B should be taken, or only\nthose files in B where there's a merge conflict. I don't know an easy way\nto do the former, but the latter I'd do like this:\n\n\t$ git diff --name-only | xargs git checkout B --\n\n-- Hannes\n"},{"id":"80074","messageId":"20080616211638.GL29404@genesis.frugalware.org","threadId":"13974","inReplyTo":"48563D6C.8060704@viscovery.net","subject":"Re: Guided merge with override","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-06-16T21:16:38Z","receivedAt":"2008-06-16T21:16:38Z","isPatch":false,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jun 16, 2008 at 12:16:12PM +0200, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> I don't think that's what Geoff needs. The 'theirs' strategy replaces the\n> entire tree by 'their' - B's - tree. But IIUC, only the subset of files\n> that are contained in B should be replaced by B's version, the rest of the\n> files should remain unchanged. This is quite different from 'theirs' strategy.\n\nThanks, I missed that difference, and sorry for the wrong suggestion.\n"},{"id":"80082","messageId":"bd6139dc0806161521p3667a44ble8573be1569986a0@mail.gmail.com","threadId":"13974","inReplyTo":"48563D6C.8060704@viscovery.net","subject":"Re: Guided merge with override","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-06-16T22:21:39Z","receivedAt":"2008-06-16T22:21:39Z","isPatch":false,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> The solution depends on whether *all* files in B should be taken, or only\n> those files in B where there's a merge conflict. I don't know an easy way\n> to do the former, but the latter I'd do like this:\n>\n>        $ git diff --name-only | xargs git checkout B --\n\nWouldn't something similar work but do a 'git ls-files' and filter it\non files that have a merge conflict?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"80085","messageId":"93c3eada0806161545m5c6e1073q5522ce31f72be9f0@mail.gmail.com","threadId":"13974","inReplyTo":"bd6139dc0806161521p3667a44ble8573be1569986a0@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Geoff Russell","fromEmail":"geoffrey.russell@gmail.com","sentAt":"2008-06-16T22:45:50Z","receivedAt":"2008-06-16T22:45:50Z","isPatch":false,"sender":{"key":"geoffrey.russell@gmail.com","avatar":"https://gravatar.com/avatar/c30f497ccfa6bf06d86f30bd2ba092a2dd124c61c6bc902f7cb5c3f6486947de?d=mp&s=160"},"body":"Thanks everybody,\n\nOn 6/17/08, Sverre Rabbelier <alturin@gmail.com> wrote:\n> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n>  > The solution depends on whether *all* files in B should be taken, or only\n>  > those files in B where there's a merge conflict. I don't know an easy way\n>  > to do the former, but the latter I'd do like this:\n>  >\n>  >        $ git diff --name-only | xargs git checkout B --\n\nThis looks like a manageable approach and better than the scripting I was\nthinking about -- ie. scan the conflict files with perl and fix them!\n\nCheers,\nGeoff\n\n>\n>\n> Wouldn't something similar work but do a 'git ls-files' and filter it\n>  on files that have a merge conflict?\n>\n>  --\n>  Cheers,\n>\n>\n>  Sverre Rabbelier\n>\n\n\n-- \n6 Fifth Ave,\nSt Morris, S.A. 5068\nAustralia\nPh: 041 8805 184 / 08 8332 5069\n"},{"id":"80101","messageId":"485756AE.9050904@viscovery.net","threadId":"13974","inReplyTo":"bd6139dc0806161521p3667a44ble8573be1569986a0@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-06-17T06:16:14Z","receivedAt":"2008-06-17T06:16:14Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Sverre Rabbelier schrieb:\n> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n>> The solution depends on whether *all* files in B should be taken, or only\n>> those files in B where there's a merge conflict. I don't know an easy way\n>> to do the former, but the latter I'd do like this:\n>>\n>>        $ git diff --name-only | xargs git checkout B --\n> \n> Wouldn't something similar work but do a 'git ls-files' and filter it\n> on files that have a merge conflict?\n\nWell, you could 'git ls-files --unmerged', but that prints the whole index\nentry, not just the name, and then you need a more complicated pipeline.\n\n-- Hannes\n"},{"id":"80115","messageId":"bd6139dc0806170153h4fba934ei62cb06e98e0280fd@mail.gmail.com","threadId":"13974","inReplyTo":"485756AE.9050904@viscovery.net","subject":"Re: Guided merge with override","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-06-17T08:53:53Z","receivedAt":"2008-06-17T08:53:53Z","isPatch":false,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Tue, Jun 17, 2008 at 8:16 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Sverre Rabbelier schrieb:\n>> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n>>> The solution depends on whether *all* files in B should be taken, or only\n>>> those files in B where there's a merge conflict. I don't know an easy way\n>>> to do the former, but the latter I'd do like this:\n>>>\n>>>        $ git diff --name-only | xargs git checkout B --\n>>\n>> Wouldn't something similar work but do a 'git ls-files' and filter it\n>> on files that have a merge conflict?\n>\n> Well, you could 'git ls-files --unmerged', but that prints the whole index\n> entry, not just the name, and then you need a more complicated pipeline.\n\nHow about 'git ls-files -t | grep \"^M \" | xargs git checkout B --',\nthat would list all files that are unmerged and check them out?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"80121","messageId":"alpine.DEB.1.00.0806171045570.6439@racer","threadId":"13974","inReplyTo":"bd6139dc0806170153h4fba934ei62cb06e98e0280fd@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-17T09:48:38Z","receivedAt":"2008-06-17T09:48:38Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 17 Jun 2008, Sverre Rabbelier wrote:\n\n> How about 'git ls-files -t | grep \"^M \" | xargs git checkout B --',\n\nYou probably meant 'sed -n \"s/^M //p\"' instead of 'grep \"^M\"', right?\n\nOf course, I think that a better way would be to ask \"git diff \n--name-only --diff-filter=U\".\n\nCiao,\nDscho\n"},{"id":"80123","messageId":"bd6139dc0806170253r5ea7844dm71d0bc407da2acc7@mail.gmail.com","threadId":"13974","inReplyTo":"alpine.DEB.1.00.0806171045570.6439@racer","subject":"Re: Guided merge with override","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-06-17T09:53:19Z","receivedAt":"2008-06-17T09:53:19Z","isPatch":false,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Tue, Jun 17, 2008 at 11:48 AM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Tue, 17 Jun 2008, Sverre Rabbelier wrote:\n>> How about 'git ls-files -t | grep \"^M \" | xargs git checkout B --',\n>\n> You probably meant 'sed -n \"s/^M //p\"' instead of 'grep \"^M\"', right?\n\nWhoops, yes, that would be a lot better :P.\n\n> Of course, I think that a better way would be to ask \"git diff\n> --name-only --diff-filter=U\".\n\nHmmm, not having an unfinished merge at hand, would that require the\nsed on top too?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"80124","messageId":"alpine.DEB.1.00.0806171117280.6439@racer","threadId":"13974","inReplyTo":"bd6139dc0806170253r5ea7844dm71d0bc407da2acc7@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-17T10:17:55Z","receivedAt":"2008-06-17T10:17:55Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 17 Jun 2008, Sverre Rabbelier wrote:\n\n> On Tue, Jun 17, 2008 at 11:48 AM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n>\n> > Of course, I think that a better way would be to ask \"git diff \n> > --name-only --diff-filter=U\".\n> \n> Hmmm, not having an unfinished merge at hand, would that require the\n> sed on top too?\n\nNope.  The \"--name-only\" says it will print only the name.\n\nCiao,\nDscho\n"},{"id":"80159","messageId":"7vve076d6t.fsf@gitster.siamese.dyndns.org","threadId":"13974","inReplyTo":"93c3eada0806161545m5c6e1073q5522ce31f72be9f0@mail.gmail.com","subject":"Re: Guided merge with override","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-17T20:04:10Z","receivedAt":"2008-06-17T20:04:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Geoff Russell\" <geoffrey.russell@gmail.com> writes:\n\n> Thanks everybody,\n>\n> On 6/17/08, Sverre Rabbelier <alturin@gmail.com> wrote:\n>> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n>>  > The solution depends on whether *all* files in B should be taken, or only\n>>  > those files in B where there's a merge conflict. I don't know an easy way\n>>  > to do the former, but the latter I'd do like this:\n>>  >\n>>  >        $ git diff --name-only | xargs git checkout B --\n>\n> This looks like a manageable approach and better than the scripting I was\n> thinking about -- ie. scan the conflict files with perl and fix them!\n\nCareful.\n\nThe above pipeline gives quite different result from \"scan the conflict\nfiles with perl and fix them\".\n\nIf the result you want from the \"scan and fix the conflicts\" approach is\nto take as much automerge as possible, and punt only on conflicting parts\nby discarding your work (side note: I hear this wish often and still I\nhave not heard satisfactory explanation why people think that could be a\nsane result, though), the above pipeline is not what you want.  It not\nonly discards your work in conflicting parts but also all your work from\neven cleanly automerged parts of a path that has conflicts.\n\nFor example, suppose the original, our version and their version are like\nthese respectively:\n\n        (orig)    (ours)     (theirs)\n        1         one        uno\n        2         2          2\n        3         3          3\n        4         4          4\n        5         5          5\n        6         6          6\n        7         7          7\n        8         eight      8\n\nIf you merge these with natural 3-way merge, you would get this:\n\n        $ git-merge-file -p ours orig theirs\n        <<<<<<< ours\n        one\n        =======\n        uno\n        >>>>>>> theirs\n        2\n        3\n        4\n        5\n        6\n        7\n        eight\n\nNote: git-merge-file mimicks the \"merge\" program from RCS suite.  The\n      three file parameters are mine, old and yours (in alphabetical order\n      as easy-to-remember mnemonic) and means \"update mine taking the\n      change that you made to old to reach yours\".\n\nThat's a conflict.  The above suggested pipeline would give \"their\"\nversion.  That means the result does not have your change s/8/eight/.\n\nIt all depends on what you really mean by take \"theirs\", but you might\nhave wanted to have this instead, with the \"scan and fix the conflicts\"\napproach you hinted in your message:\n\n        $ git-merge-file -p --theirs ours orig theirs\n        uno\n        2\n        3\n        4\n        5\n        6\n        7\n        eight\n\nThat retains your change in non-conflicting part while favoring their\nchange where conflicts are.\n\nNo, neither --theirs nor --ours option exists in your version of git.\nBut here is a patch to add it to git-merge-file.\n\n---\n\n builtin-merge-file.c |   10 ++++++++--\n xdiff/xdiff.h        |    8 +++++++-\n xdiff/xmerge.c       |   24 ++++++++++++++++--------\n 3 files changed, 31 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin-merge-file.c b/builtin-merge-file.c\nindex 3605960..7d4ca8c 100644\n--- a/builtin-merge-file.c\n+++ b/builtin-merge-file.c\n@@ -4,7 +4,7 @@\n #include \"xdiff-interface.h\"\n \n static const char merge_file_usage[] =\n-\"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2\";\n+\"git merge-file [-p | --stdout] [-q | --quiet] [--ours|--theirs] [-L name1 [-L orig [-L name2]]] file1 orig_file file2\";\n \n int cmd_merge_file(int argc, const char **argv, const char *prefix)\n {\n@@ -13,6 +13,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \tmmbuffer_t result = {NULL, 0};\n \txpparam_t xpp = {XDF_NEED_MINIMAL};\n \tint ret = 0, i = 0, to_stdout = 0;\n+\tint flags, favor = 0;\n \n \twhile (argc > 4) {\n \t\tif (!strcmp(argv[1], \"-L\") && i < 3) {\n@@ -25,6 +26,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-q\") ||\n \t\t\t\t!strcmp(argv[1], \"--quiet\"))\n \t\t\tfreopen(\"/dev/null\", \"w\", stderr);\n+\t\telse if (!strcmp(argv[1], \"--ours\"))\n+\t\t\tfavor = XDL_MERGE_FAVOR_OURS;\n+\t\telse if (!strcmp(argv[1], \"--theirs\"))\n+\t\t\tfavor = XDL_MERGE_FAVOR_THEIRS;\n \t\telse\n \t\t\tusage(merge_file_usage);\n \t\targc--;\n@@ -45,8 +50,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t\t\targv[i + 1]);\n \t}\n \n+\tflags = XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS_ALNUM, favor);\n \tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);\n+\t\t\t&xpp, flags, &result);\n \n \tfor (i = 0; i < 3; i++)\n \t\tfree(mmfs[i].ptr);\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 413082e..d40cf21 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -99,9 +99,15 @@ long xdl_mmfile_size(mmfile_t *mmf);\n int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \t     xdemitconf_t const *xecfg, xdemitcb_t *ecb);\n \n+#define XDL_MERGE_FAVOR_OURS\t\t1\n+#define XDL_MERGE_FAVOR_THEIRS\t\t2\n+#define XDL_MERGE_FAVOR(flag)\t\t(((flag)>>4) & 03)\n+#define XDL_MERGE_LEVEL(flag)\t\t((flag) & 07)\n+#define XDL_MERGE_FLAGS(level,flag)\t((level) | ((flag)<<4))\n+\n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int level, mmbuffer_t *result);\n+\t\txpparam_t const *xpp, int flag, mmbuffer_t *result);\n \n #ifdef __cplusplus\n }\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 82b3573..88c29ae 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -114,7 +114,9 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)\n }\n \n static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n-\t\txdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)\n+\t\t\t\t xdfenv_t *xe2, const char *name2,\n+\t\t\t\t int favor,\n+\t\t\t\t xdmerge_t *m, char *dest)\n {\n \tconst int marker_size = 7;\n \tint marker1_size = (name1 ? strlen(name1) + 1 : 0);\n@@ -124,6 +126,9 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n \tint size, i1, j;\n \n \tfor (size = i1 = 0; m; m = m->next) {\n+\t\tif (favor && !m->mode)\n+\t\t\tm->mode = favor;\n+\n \t\tif (m->mode == 0) {\n \t\t\tsize += xdl_recs_copy(xe1, i1, m->i1 - i1, 0,\n \t\t\t\t\tdest ? dest + size : NULL);\n@@ -322,8 +327,9 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,\n  * returns < 0 on error, == 0 for no conflicts, else number of conflicts\n  */\n static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n-\t\txdfenv_t *xe2, xdchange_t *xscr2, const char *name2,\n-\t\tint level, xpparam_t const *xpp, mmbuffer_t *result) {\n+\t\t\txdfenv_t *xe2, xdchange_t *xscr2, const char *name2,\n+\t\t\tint level, int favor,\n+\t\t\txpparam_t const *xpp, mmbuffer_t *result) {\n \txdmerge_t *changes, *c;\n \tint i1, i2, chg1, chg2;\n \n@@ -430,25 +436,27 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t/* output */\n \tif (result) {\n \t\tint size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,\n-\t\t\tchanges, NULL);\n+\t\t\t\t\t\t favor, changes, NULL);\n \t\tresult->ptr = xdl_malloc(size);\n \t\tif (!result->ptr) {\n \t\t\txdl_cleanup_merge(changes);\n \t\t\treturn -1;\n \t\t}\n \t\tresult->size = size;\n-\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,\n-\t\t\t\tresult->ptr);\n+\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2,\n+\t\t\t\t      favor, changes, result->ptr);\n \t}\n \treturn xdl_cleanup_merge(changes);\n }\n \n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int level, mmbuffer_t *result) {\n+\t\txpparam_t const *xpp, int flag, mmbuffer_t *result) {\n \txdchange_t *xscr1, *xscr2;\n \txdfenv_t xe1, xe2;\n \tint status;\n+\tint level = XDL_MERGE_LEVEL(flag);\n+\tint favor = XDL_MERGE_FAVOR(flag);\n \n \tresult->ptr = NULL;\n \tresult->size = 0;\n@@ -482,7 +490,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\t} else {\n \t\t\tstatus = xdl_do_merge(&xe1, xscr1, name1,\n \t\t\t\t\t      &xe2, xscr2, name2,\n-\t\t\t\t\t      level, xpp, result);\n+\t\t\t\t\t      level, favor, xpp, result);\n \t\t}\n \t\txdl_free_script(xscr1);\n \t\txdl_free_script(xscr2);\n"},{"id":"80224","messageId":"alpine.DEB.1.00.0806181618070.6439@racer","threadId":"13974","inReplyTo":"7vve076d6t.fsf@gitster.siamese.dyndns.org","subject":"Re: Guided merge with override","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-18T15:19:00Z","receivedAt":"2008-06-18T15:19:00Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 17 Jun 2008, Junio C Hamano wrote:\n\n> No, neither --theirs nor --ours option exists in your version of git. \n> But here is a patch to add it to git-merge-file.\n\nLooks good, thanks!  Just to be safe, this should be accompanied by tet \ncases.  But I did not see anything wrong with the patch.\n\nCiao,\nDscho\n"},{"id":"80226","messageId":"alpine.DEB.1.00.0806181627260.6439@racer","threadId":"13974","inReplyTo":"alpine.DEB.1.00.0806181618070.6439@racer","subject":"Re: Guided merge with override","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-18T15:28:42Z","receivedAt":"2008-06-18T15:28:42Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 18 Jun 2008, Johannes Schindelin wrote:\n\n> On Tue, 17 Jun 2008, Junio C Hamano wrote:\n> \n> > No, neither --theirs nor --ours option exists in your version of git. \n> > But here is a patch to add it to git-merge-file.\n> \n> Looks good, thanks!  Just to be safe, this should be accompanied by tet \n> cases.  But I did not see anything wrong with the patch.\n\nThinking about this again, there could be a problem: in case of complex \nmerges, it is possible that the sides are switched around for an \nintermediate merge.  IOW you'd expect it to take \"theirs\", but it really \ntakes \"ours\".\n\nHrm.\n\nCiao,\nDscho\n"},{"id":"80230","messageId":"7viqw6zovi.fsf@gitster.siamese.dyndns.org","threadId":"13974","inReplyTo":"alpine.DEB.1.00.0806181627260.6439@racer","subject":"Re: Guided merge with override","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-18T16:31:13Z","receivedAt":"2008-06-18T16:31:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Thinking about this again, there could be a problem: in case of complex \n> merges, it is possible that the sides are switched around for an \n> intermediate merge.  IOW you'd expect it to take \"theirs\", but it really \n> takes \"ours\".\n\nAre you thinking about using this in merge-recursive?\n\nI do not think there is any reason to use this during intermediate merges\ndone inside merge-recursive.  The point of recursive merge is to create a\nneutral intermediate merge result, with conflicts and all.  Do this only\nduring the final round and you are fine (for some definition of \"fine\" ---\nI still have not heard a convincing argument as to why it is even a good\nthing to be able to take one side for only parts that did conflict, while\ntaking the change from the other side in places that did not).\n"},{"id":"80241","messageId":"alpine.DEB.1.00.0806182027240.6439@racer","threadId":"13974","inReplyTo":"7viqw6zovi.fsf@gitster.siamese.dyndns.org","subject":"Re: Guided merge with override","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-18T19:29:35Z","receivedAt":"2008-06-18T19:29:35Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 18 Jun 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > Thinking about this again, there could be a problem: in case of complex \n> > merges, it is possible that the sides are switched around for an \n> > intermediate merge.  IOW you'd expect it to take \"theirs\", but it really \n> > takes \"ours\".\n> \n> Are you thinking about using this in merge-recursive?\n\nIndeed I was.\n\n> I do not think there is any reason to use this during intermediate \n> merges done inside merge-recursive.\n\nThat is right, but for some stupid reason I did not realize that \ngit-merge-file is not even called by merge-recursive.\n\nSo the accompanying patch for merge-recursive would use the --theirs or \n--ours logic only in the !index_only case, i.e. the final merge.\n\nAnd I guess we'd have similar logic as for merge-subtree, introducing \nmerge-recursive-ours and merge-recursive-theirs.\n\nVery nice.\n\nCiao,\nDscho\n"},{"id":"80441","messageId":"7vfxr8o8sx.fsf_-_@gitster.siamese.dyndns.org","threadId":"13974","inReplyTo":"7viqw6zovi.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 1/2] git-merge-file --ours, --theirs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-20T07:38:22Z","receivedAt":"2008-06-20T07:38:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often people want their conflicting merges autoresolved by favouring\nupstream changes (or their own --- it's the same thing), and hinted to run\n\"git diff --name-only | xargs git checkout MERGE_HEAD --\".  This is\nessentially to accept automerge results for the paths that are fully\nresolved automatically while taking their version of the file in full for\npaths that have conflicts.\n\nThis is problematic on two counts.\n\nOne problem is that this is not exactly what these people want.  They\nusually want to salvage as much automerge result as possible.  In\nparticular, they want to keep autoresolved parts in conflicting paths, as\nwell as the paths that are fully autoresolved.\n\nThis patch teaches two new modes of operation to the lowest-lever merge\nmachinery, xdl_merge().  Instead of leaving the conflicted lines from both\nsides enclosed in <<<, ===, and >>> markers, you can tell the conflicts to\nbe resolved favouring your side or their side of changes.\n\nA larger problem is that this tends to encourage a bad workflow by\nallowing them to record such a mixed up half-merge result as a full commit\nwithout auditing.  This commit does not tackle this latter issue.  In git,\nwe usually give long enough rope to users with strange wishes as long as\nthe risky features is not on by default.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * Essentially the same patch but with documentation.\n\n Documentation/git-merge-file.txt |   12 ++++++++++--\n builtin-merge-file.c             |   10 ++++++++--\n xdiff/xdiff.h                    |    8 +++++++-\n xdiff/xmerge.c                   |   24 ++++++++++++++++--------\n 4 files changed, 41 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt\nindex 149f131..87e07d3 100644\n--- a/Documentation/git-merge-file.txt\n+++ b/Documentation/git-merge-file.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n --------\n [verse]\n 'git-merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]\n-\t[-p|--stdout] [-q|--quiet] <current-file> <base-file> <other-file>\n+\t[--ours|--theirs] [-p|--stdout] [-q|--quiet]\n+\t<current-file> <base-file> <other-file>\n \n \n DESCRIPTION\n@@ -34,7 +35,9 @@ normally outputs a warning and brackets the conflict with <<<<<<< and\n \t>>>>>>> B\n \n If there are conflicts, the user should edit the result and delete one of\n-the alternatives.\n+the alternatives.  When `--ours` or `--theirs` option is in effect, however,\n+these conflicts are resolved favouring lines from `<current-file>` or\n+lines from `<other-file>` respectively.\n \n The exit value of this program is negative on error, and the number of\n conflicts otherwise. If the merge was clean, the exit value is 0.\n@@ -62,6 +65,11 @@ OPTIONS\n -q::\n \tQuiet;  do  not  warn about conflicts.\n \n+--ours::\n+--theirs::\n+\tInstead of leaving conflicts in the file, resolve conflicts\n+\tfavouring our (or their) side of the lines.\n+\n \n EXAMPLES\n --------\ndiff --git a/builtin-merge-file.c b/builtin-merge-file.c\nindex 3605960..7d4ca8c 100644\n--- a/builtin-merge-file.c\n+++ b/builtin-merge-file.c\n@@ -4,7 +4,7 @@\n #include \"xdiff-interface.h\"\n \n static const char merge_file_usage[] =\n-\"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2\";\n+\"git merge-file [-p | --stdout] [-q | --quiet] [--ours|--theirs] [-L name1 [-L orig [-L name2]]] file1 orig_file file2\";\n \n int cmd_merge_file(int argc, const char **argv, const char *prefix)\n {\n@@ -13,6 +13,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \tmmbuffer_t result = {NULL, 0};\n \txpparam_t xpp = {XDF_NEED_MINIMAL};\n \tint ret = 0, i = 0, to_stdout = 0;\n+\tint flags, favor = 0;\n \n \twhile (argc > 4) {\n \t\tif (!strcmp(argv[1], \"-L\") && i < 3) {\n@@ -25,6 +26,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\telse if (!strcmp(argv[1], \"-q\") ||\n \t\t\t\t!strcmp(argv[1], \"--quiet\"))\n \t\t\tfreopen(\"/dev/null\", \"w\", stderr);\n+\t\telse if (!strcmp(argv[1], \"--ours\"))\n+\t\t\tfavor = XDL_MERGE_FAVOR_OURS;\n+\t\telse if (!strcmp(argv[1], \"--theirs\"))\n+\t\t\tfavor = XDL_MERGE_FAVOR_THEIRS;\n \t\telse\n \t\t\tusage(merge_file_usage);\n \t\targc--;\n@@ -45,8 +50,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t\t\targv[i + 1]);\n \t}\n \n+\tflags = XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS_ALNUM, favor);\n \tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);\n+\t\t\t&xpp, flags, &result);\n \n \tfor (i = 0; i < 3; i++)\n \t\tfree(mmfs[i].ptr);\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 413082e..d40cf21 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -99,9 +99,15 @@ long xdl_mmfile_size(mmfile_t *mmf);\n int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \t     xdemitconf_t const *xecfg, xdemitcb_t *ecb);\n \n+#define XDL_MERGE_FAVOR_OURS\t\t1\n+#define XDL_MERGE_FAVOR_THEIRS\t\t2\n+#define XDL_MERGE_FAVOR(flag)\t\t(((flag)>>4) & 03)\n+#define XDL_MERGE_LEVEL(flag)\t\t((flag) & 07)\n+#define XDL_MERGE_FLAGS(level,flag)\t((level) | ((flag)<<4))\n+\n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int level, mmbuffer_t *result);\n+\t\txpparam_t const *xpp, int flag, mmbuffer_t *result);\n \n #ifdef __cplusplus\n }\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 82b3573..88c29ae 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -114,7 +114,9 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)\n }\n \n static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n-\t\txdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)\n+\t\t\t\t xdfenv_t *xe2, const char *name2,\n+\t\t\t\t int favor,\n+\t\t\t\t xdmerge_t *m, char *dest)\n {\n \tconst int marker_size = 7;\n \tint marker1_size = (name1 ? strlen(name1) + 1 : 0);\n@@ -124,6 +126,9 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n \tint size, i1, j;\n \n \tfor (size = i1 = 0; m; m = m->next) {\n+\t\tif (favor && !m->mode)\n+\t\t\tm->mode = favor;\n+\n \t\tif (m->mode == 0) {\n \t\t\tsize += xdl_recs_copy(xe1, i1, m->i1 - i1, 0,\n \t\t\t\t\tdest ? dest + size : NULL);\n@@ -322,8 +327,9 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,\n  * returns < 0 on error, == 0 for no conflicts, else number of conflicts\n  */\n static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n-\t\txdfenv_t *xe2, xdchange_t *xscr2, const char *name2,\n-\t\tint level, xpparam_t const *xpp, mmbuffer_t *result) {\n+\t\t\txdfenv_t *xe2, xdchange_t *xscr2, const char *name2,\n+\t\t\tint level, int favor,\n+\t\t\txpparam_t const *xpp, mmbuffer_t *result) {\n \txdmerge_t *changes, *c;\n \tint i1, i2, chg1, chg2;\n \n@@ -430,25 +436,27 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t/* output */\n \tif (result) {\n \t\tint size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,\n-\t\t\tchanges, NULL);\n+\t\t\t\t\t\t favor, changes, NULL);\n \t\tresult->ptr = xdl_malloc(size);\n \t\tif (!result->ptr) {\n \t\t\txdl_cleanup_merge(changes);\n \t\t\treturn -1;\n \t\t}\n \t\tresult->size = size;\n-\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,\n-\t\t\t\tresult->ptr);\n+\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2,\n+\t\t\t\t      favor, changes, result->ptr);\n \t}\n \treturn xdl_cleanup_merge(changes);\n }\n \n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int level, mmbuffer_t *result) {\n+\t\txpparam_t const *xpp, int flag, mmbuffer_t *result) {\n \txdchange_t *xscr1, *xscr2;\n \txdfenv_t xe1, xe2;\n \tint status;\n+\tint level = XDL_MERGE_LEVEL(flag);\n+\tint favor = XDL_MERGE_FAVOR(flag);\n \n \tresult->ptr = NULL;\n \tresult->size = 0;\n@@ -482,7 +490,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\t} else {\n \t\t\tstatus = xdl_do_merge(&xe1, xscr1, name1,\n \t\t\t\t\t      &xe2, xscr2, name2,\n-\t\t\t\t\t      level, xpp, result);\n+\t\t\t\t\t      level, favor, xpp, result);\n \t\t}\n \t\txdl_free_script(xscr1);\n \t\txdl_free_script(xscr2);\n-- \n1.5.6.6.gd3e97\n"},{"id":"80442","messageId":"7vbq1wo8ck.fsf_-_@gitster.siamese.dyndns.org","threadId":"13974","inReplyTo":"7vfxr8o8sx.fsf_-_@gitster.siamese.dyndns.org","subject":"[PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-20T07:48:11Z","receivedAt":"2008-06-20T07:48:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This 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 Makefile                     |    3 ++\n builtin-merge-recursive.c    |   37 ++++++++++++++++++++++++---\n git-merge.sh                 |    3 +-\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(+), 15 deletions(-)\n create mode 100755 t/t6034-merge-ours-theirs.sh\n\ndiff --git a/Makefile b/Makefile\nindex b003e3e..82d2892 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -304,6 +304,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 4aa28a1..a355e7a 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@@ -642,6 +646,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@@ -650,9 +655,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@@ -1171,7 +1193,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@@ -1379,11 +1401,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/git-merge.sh b/git-merge.sh\nindex 8026ccf..39b5cd9 100755\n--- a/git-merge.sh\n+++ b/git-merge.sh\n@@ -31,10 +31,11 @@ LF='\n '\n \n all_strategies='recur recursive octopus resolve stupid ours subtree'\n+all_strategies=\"$all_strategies recursive-ours recursive-theirs\"\n default_twohead_strategies='recursive'\n default_octopus_strategies='octopus'\n no_fast_forward_strategies='subtree ours'\n-no_trivial_strategies='recursive recur subtree ours'\n+no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs'\n use_strategies=\n \n allow_fast_forward=t\ndiff --git a/git.c b/git.c\nindex 59f0fcc..44cb8eb 100644\n--- a/git.c\n+++ b/git.c\n@@ -328,6 +328,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.6.gd3e97\n"},{"id":"80474","messageId":"alpine.DEB.1.00.0806201351370.6439@racer","threadId":"13974","inReplyTo":"7vbq1wo8ck.fsf_-_@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-20T12:58:52Z","receivedAt":"2008-06-20T12:58:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 20 Jun 2008, Junio C Hamano wrote:\n\n> diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c\n> index 4aa28a1..a355e7a 100644\n> --- a/builtin-merge-recursive.c\n> +++ b/builtin-merge-recursive.c\n> @@ -650,9 +655,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\nHrm.  I would have preferred something like this:\n\n\tif (!index_only && merge_recursive_variants == MERGE_RECURSIVE_OURS)\n\t\tfavor = XDL_MERGE_FAVOR_OURS;\n\tif (!index_only && merge_recursive_variants == MERGE_RECURSIVE_THEIRS)\n\t\tfavor = XDL_MERGE_FAVOR_THEIRS;\n\telse\n\t\tfavor = 0;\n\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\nSorry, but in my opinion this flag mangling makes the whole code uglier.  \nWhy not just add another parameter?\n\nOr if you are really concerned about future enhancements to ll_merge(), \nuse a struct.\n\n> @@ -1379,11 +1401,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\nThis just cries out loud for a new function suffixcmp().\n\nI will not say anything about the long lines in git-merge.sh, since I \nfully expect builtin-merge to happen Real Soon Now.\n\nAnyhow, your comments about this driving the wrong workflow still apply.  \nMaybe we want to display them really, really prominently in \nDocumentation/merge-strategies.txt.\n\nCiao,\nDscho\n"},{"id":"80541","messageId":"7vy74z9l3l.fsf@gitster.siamese.dyndns.org","threadId":"13974","inReplyTo":"alpine.DEB.1.00.0806201351370.6439@racer","subject":"Re: [PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-21T09:46:22Z","receivedAt":"2008-06-21T09:46:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> @@ -1379,11 +1401,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>\n> This just cries out loud for a new function suffixcmp().\n\nActually, I think \"git-merge-recursive-theirs\" is a mistake.  We should\nbite the bullet and give \"git-merge\" an ability to pass backend specific\nparameters to \"git-merge-recursive\".  The new convention could be that\nanything that begins with -X is passed to the backend.\n\nE.g.\n\n\tgit merge -Xfavor=theirs foo\n        git merge -Xsubtree=/=gitk-git paulus\n\nAs you noticed already, subtree is just a funny optional behaviour\nattached to recursive, so are theirs and ours.  The above two would invoke\ngit-merge-recursive like so:\n\n\tgit merge-recursive -Xfavor=theirs <base> -- HEAD MERGE_HEAD\n\tgit merge-recursive -Xsubtree=/=gitk-git <base> -- HEAD MERGE_HEAD\n\nWe could even mix these two if we are ambitious.\n"},{"id":"80553","messageId":"alpine.DEB.1.00.0806211728090.6439@racer","threadId":"13974","inReplyTo":"7vy74z9l3l.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-21T16:29:24Z","receivedAt":"2008-06-21T16:29:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 21 Jun 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> @@ -1379,11 +1401,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> >\n> > This just cries out loud for a new function suffixcmp().\n> \n> Actually, I think \"git-merge-recursive-theirs\" is a mistake.  We should\n> bite the bullet and give \"git-merge\" an ability to pass backend specific\n> parameters to \"git-merge-recursive\".\n\nFair enough.\n\n> The new convention could be that anything that begins with -X is passed \n> to the backend.\n> \n> E.g.\n> \n> \tgit merge -Xfavor=theirs foo\n>         git merge -Xsubtree=/=gitk-git paulus\n> \n> As you noticed already, subtree is just a funny optional behaviour\n> attached to recursive, so are theirs and ours.  The above two would invoke\n> git-merge-recursive like so:\n> \n> \tgit merge-recursive -Xfavor=theirs <base> -- HEAD MERGE_HEAD\n> \tgit merge-recursive -Xsubtree=/=gitk-git <base> -- HEAD MERGE_HEAD\n> \n> We could even mix these two if we are ambitious.\n\nLooks fine to me.  And much cleaner than the hardlinking.\n\nCiao,\nDscho\n"},{"id":"80554","messageId":"m3zlpeloah.fsf@localhost.localdomain","threadId":"13974","inReplyTo":"7vy74z9l3l.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/2] git-merge-recursive-{ours,theirs}","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-21T16:56:45Z","receivedAt":"2008-06-21T16:56:45Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Actually, I think \"git-merge-recursive-theirs\" is a mistake.  We should\n> bite the bullet and give \"git-merge\" an ability to pass backend specific\n> parameters to \"git-merge-recursive\".  The new convention could be that\n> anything that begins with -X is passed to the backend.\n> \n> E.g.\n> \n> \tgit merge -Xfavor=theirs foo\n>       git merge -Xsubtree=/=gitk-git paulus\n\nGaaah... only after reading it for third time I see that it isn't\nsome funky \"=/=\" symbol, but subtree with grafing '/' in one side\nto 'gitk-git' subdirectory in other side.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"}]}