* Guided merge with override @ 2008-06-16 4:16 Geoff Russell 2008-06-16 9:25 ` Miklos Vajna 0 siblings, 1 reply; 23+ messages in thread From: Geoff Russell @ 2008-06-16 4:16 UTC (permalink / raw) To: git I have a two repositories A and B. B is a tiny subset of the files in A and all have been modified. If I do a "git pull B" into A, I get conflicts. I always want to resolve these by accepting the version from B. Is there a magic "override" switch to let me do this? Cheers, Geoff Russell ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 4:16 Guided merge with override Geoff Russell @ 2008-06-16 9:25 ` Miklos Vajna 2008-06-16 10:16 ` Johannes Sixt 0 siblings, 1 reply; 23+ messages in thread From: Miklos Vajna @ 2008-06-16 9:25 UTC (permalink / raw) To: Geoff Russell; +Cc: git [-- Attachment #1: Type: text/plain, Size: 512 bytes --] On Mon, Jun 16, 2008 at 01:46:38PM +0930, Geoff Russell <geoffrey.russell@gmail.com> wrote: > I have a two repositories A and B. B is a tiny subset of the files in > A and all have been > modified. If I do a "git pull B" into A, I get conflicts. I always > want to resolve these > by accepting the version from B. Is there a magic "override" switch to > let me do this? There was a thread about this: http://thread.gmane.org/gmane.comp.version-control.git/84047 and then you can do a git pull -s theirs B. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 9:25 ` Miklos Vajna @ 2008-06-16 10:16 ` Johannes Sixt 2008-06-16 21:16 ` Miklos Vajna 2008-06-16 22:21 ` Sverre Rabbelier 0 siblings, 2 replies; 23+ messages in thread From: Johannes Sixt @ 2008-06-16 10:16 UTC (permalink / raw) To: Miklos Vajna; +Cc: Geoff Russell, git Miklos Vajna schrieb: > On Mon, Jun 16, 2008 at 01:46:38PM +0930, Geoff Russell <geoffrey.russell@gmail.com> wrote: >> I have a two repositories A and B. B is a tiny subset of the files in >> A and all have been >> modified. If I do a "git pull B" into A, I get conflicts. I always >> want to resolve these >> by accepting the version from B. Is there a magic "override" switch to >> let me do this? > > There was a thread about this: > > http://thread.gmane.org/gmane.comp.version-control.git/84047 > > and then you can do a git pull -s theirs B. I don't think that's what Geoff needs. The 'theirs' strategy replaces the entire tree by 'their' - B's - tree. But IIUC, only the subset of files that are contained in B should be replaced by B's version, the rest of the files should remain unchanged. This is quite different from 'theirs' strategy. The solution depends on whether *all* files in B should be taken, or only those files in B where there's a merge conflict. I don't know an easy way to do the former, but the latter I'd do like this: $ git diff --name-only | xargs git checkout B -- -- Hannes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 10:16 ` Johannes Sixt @ 2008-06-16 21:16 ` Miklos Vajna 2008-06-16 22:21 ` Sverre Rabbelier 1 sibling, 0 replies; 23+ messages in thread From: Miklos Vajna @ 2008-06-16 21:16 UTC (permalink / raw) To: Johannes Sixt; +Cc: Geoff Russell, git [-- Attachment #1: Type: text/plain, Size: 465 bytes --] On Mon, Jun 16, 2008 at 12:16:12PM +0200, Johannes Sixt <j.sixt@viscovery.net> wrote: > I don't think that's what Geoff needs. The 'theirs' strategy replaces the > entire tree by 'their' - B's - tree. But IIUC, only the subset of files > that are contained in B should be replaced by B's version, the rest of the > files should remain unchanged. This is quite different from 'theirs' strategy. Thanks, I missed that difference, and sorry for the wrong suggestion. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 10:16 ` Johannes Sixt 2008-06-16 21:16 ` Miklos Vajna @ 2008-06-16 22:21 ` Sverre Rabbelier 2008-06-16 22:45 ` Geoff Russell 2008-06-17 6:16 ` Guided merge with override Johannes Sixt 1 sibling, 2 replies; 23+ messages in thread From: Sverre Rabbelier @ 2008-06-16 22:21 UTC (permalink / raw) To: Johannes Sixt; +Cc: Miklos Vajna, Geoff Russell, git On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote: > The solution depends on whether *all* files in B should be taken, or only > those files in B where there's a merge conflict. I don't know an easy way > to do the former, but the latter I'd do like this: > > $ git diff --name-only | xargs git checkout B -- Wouldn't something similar work but do a 'git ls-files' and filter it on files that have a merge conflict? -- Cheers, Sverre Rabbelier ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 22:21 ` Sverre Rabbelier @ 2008-06-16 22:45 ` Geoff Russell 2008-06-17 20:04 ` Junio C Hamano 2008-06-17 6:16 ` Guided merge with override Johannes Sixt 1 sibling, 1 reply; 23+ messages in thread From: Geoff Russell @ 2008-06-16 22:45 UTC (permalink / raw) To: sverre; +Cc: Johannes Sixt, Miklos Vajna, git Thanks everybody, On 6/17/08, Sverre Rabbelier <alturin@gmail.com> wrote: > On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote: > > The solution depends on whether *all* files in B should be taken, or only > > those files in B where there's a merge conflict. I don't know an easy way > > to do the former, but the latter I'd do like this: > > > > $ git diff --name-only | xargs git checkout B -- This looks like a manageable approach and better than the scripting I was thinking about -- ie. scan the conflict files with perl and fix them! Cheers, Geoff > > > Wouldn't something similar work but do a 'git ls-files' and filter it > on files that have a merge conflict? > > -- > Cheers, > > > Sverre Rabbelier > -- 6 Fifth Ave, St Morris, S.A. 5068 Australia Ph: 041 8805 184 / 08 8332 5069 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 22:45 ` Geoff Russell @ 2008-06-17 20:04 ` Junio C Hamano 2008-06-18 15:19 ` Johannes Schindelin 0 siblings, 1 reply; 23+ messages in thread From: Junio C Hamano @ 2008-06-17 20:04 UTC (permalink / raw) To: geoffrey.russell Cc: Johannes Schindelin, sverre, Johannes Sixt, Miklos Vajna, git "Geoff Russell" <geoffrey.russell@gmail.com> writes: > Thanks everybody, > > On 6/17/08, Sverre Rabbelier <alturin@gmail.com> wrote: >> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote: >> > The solution depends on whether *all* files in B should be taken, or only >> > those files in B where there's a merge conflict. I don't know an easy way >> > to do the former, but the latter I'd do like this: >> > >> > $ git diff --name-only | xargs git checkout B -- > > This looks like a manageable approach and better than the scripting I was > thinking about -- ie. scan the conflict files with perl and fix them! Careful. The above pipeline gives quite different result from "scan the conflict files with perl and fix them". If the result you want from the "scan and fix the conflicts" approach is to take as much automerge as possible, and punt only on conflicting parts by discarding your work (side note: I hear this wish often and still I have not heard satisfactory explanation why people think that could be a sane result, though), the above pipeline is not what you want. It not only discards your work in conflicting parts but also all your work from even cleanly automerged parts of a path that has conflicts. For example, suppose the original, our version and their version are like these respectively: (orig) (ours) (theirs) 1 one uno 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 eight 8 If you merge these with natural 3-way merge, you would get this: $ git-merge-file -p ours orig theirs <<<<<<< ours one ======= uno >>>>>>> theirs 2 3 4 5 6 7 eight Note: git-merge-file mimicks the "merge" program from RCS suite. The three file parameters are mine, old and yours (in alphabetical order as easy-to-remember mnemonic) and means "update mine taking the change that you made to old to reach yours". That's a conflict. The above suggested pipeline would give "their" version. That means the result does not have your change s/8/eight/. It all depends on what you really mean by take "theirs", but you might have wanted to have this instead, with the "scan and fix the conflicts" approach you hinted in your message: $ git-merge-file -p --theirs ours orig theirs uno 2 3 4 5 6 7 eight That retains your change in non-conflicting part while favoring their change where conflicts are. No, neither --theirs nor --ours option exists in your version of git. But here is a patch to add it to git-merge-file. --- builtin-merge-file.c | 10 ++++++++-- xdiff/xdiff.h | 8 +++++++- xdiff/xmerge.c | 24 ++++++++++++++++-------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/builtin-merge-file.c b/builtin-merge-file.c index 3605960..7d4ca8c 100644 --- a/builtin-merge-file.c +++ b/builtin-merge-file.c @@ -4,7 +4,7 @@ #include "xdiff-interface.h" static const char merge_file_usage[] = -"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"; +"git merge-file [-p | --stdout] [-q | --quiet] [--ours|--theirs] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"; int cmd_merge_file(int argc, const char **argv, const char *prefix) { @@ -13,6 +13,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) mmbuffer_t result = {NULL, 0}; xpparam_t xpp = {XDF_NEED_MINIMAL}; int ret = 0, i = 0, to_stdout = 0; + int flags, favor = 0; while (argc > 4) { if (!strcmp(argv[1], "-L") && i < 3) { @@ -25,6 +26,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--quiet")) freopen("/dev/null", "w", stderr); + else if (!strcmp(argv[1], "--ours")) + favor = XDL_MERGE_FAVOR_OURS; + else if (!strcmp(argv[1], "--theirs")) + favor = XDL_MERGE_FAVOR_THEIRS; else usage(merge_file_usage); argc--; @@ -45,8 +50,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) argv[i + 1]); } + flags = XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS_ALNUM, favor); ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2], - &xpp, XDL_MERGE_ZEALOUS_ALNUM, &result); + &xpp, flags, &result); for (i = 0; i < 3; i++) free(mmfs[i].ptr); diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 413082e..d40cf21 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -99,9 +99,15 @@ long xdl_mmfile_size(mmfile_t *mmf); int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); +#define XDL_MERGE_FAVOR_OURS 1 +#define XDL_MERGE_FAVOR_THEIRS 2 +#define XDL_MERGE_FAVOR(flag) (((flag)>>4) & 03) +#define XDL_MERGE_LEVEL(flag) ((flag) & 07) +#define XDL_MERGE_FLAGS(level,flag) ((level) | ((flag)<<4)) + int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, mmfile_t *mf2, const char *name2, - xpparam_t const *xpp, int level, mmbuffer_t *result); + xpparam_t const *xpp, int flag, mmbuffer_t *result); #ifdef __cplusplus } diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 82b3573..88c29ae 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -114,7 +114,9 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) } static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, - xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest) + xdfenv_t *xe2, const char *name2, + int favor, + xdmerge_t *m, char *dest) { const int marker_size = 7; int marker1_size = (name1 ? strlen(name1) + 1 : 0); @@ -124,6 +126,9 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, int size, i1, j; for (size = i1 = 0; m; m = m->next) { + if (favor && !m->mode) + m->mode = favor; + if (m->mode == 0) { size += xdl_recs_copy(xe1, i1, m->i1 - i1, 0, dest ? dest + size : NULL); @@ -322,8 +327,9 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m, * returns < 0 on error, == 0 for no conflicts, else number of conflicts */ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1, - xdfenv_t *xe2, xdchange_t *xscr2, const char *name2, - int level, xpparam_t const *xpp, mmbuffer_t *result) { + xdfenv_t *xe2, xdchange_t *xscr2, const char *name2, + int level, int favor, + xpparam_t const *xpp, mmbuffer_t *result) { xdmerge_t *changes, *c; int i1, i2, chg1, chg2; @@ -430,25 +436,27 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1, /* output */ if (result) { int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2, - changes, NULL); + favor, changes, NULL); result->ptr = xdl_malloc(size); if (!result->ptr) { xdl_cleanup_merge(changes); return -1; } result->size = size; - xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes, - result->ptr); + xdl_fill_merge_buffer(xe1, name1, xe2, name2, + favor, changes, result->ptr); } return xdl_cleanup_merge(changes); } int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, mmfile_t *mf2, const char *name2, - xpparam_t const *xpp, int level, mmbuffer_t *result) { + xpparam_t const *xpp, int flag, mmbuffer_t *result) { xdchange_t *xscr1, *xscr2; xdfenv_t xe1, xe2; int status; + int level = XDL_MERGE_LEVEL(flag); + int favor = XDL_MERGE_FAVOR(flag); result->ptr = NULL; result->size = 0; @@ -482,7 +490,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, } else { status = xdl_do_merge(&xe1, xscr1, name1, &xe2, xscr2, name2, - level, xpp, result); + level, favor, xpp, result); } xdl_free_script(xscr1); xdl_free_script(xscr2); ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-17 20:04 ` Junio C Hamano @ 2008-06-18 15:19 ` Johannes Schindelin 2008-06-18 15:28 ` Johannes Schindelin 0 siblings, 1 reply; 23+ messages in thread From: Johannes Schindelin @ 2008-06-18 15:19 UTC (permalink / raw) To: Junio C Hamano; +Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Hi, On Tue, 17 Jun 2008, Junio C Hamano wrote: > No, neither --theirs nor --ours option exists in your version of git. > But here is a patch to add it to git-merge-file. Looks good, thanks! Just to be safe, this should be accompanied by tet cases. But I did not see anything wrong with the patch. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-18 15:19 ` Johannes Schindelin @ 2008-06-18 15:28 ` Johannes Schindelin 2008-06-18 16:31 ` Junio C Hamano 0 siblings, 1 reply; 23+ messages in thread From: Johannes Schindelin @ 2008-06-18 15:28 UTC (permalink / raw) To: Junio C Hamano; +Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Hi, On Wed, 18 Jun 2008, Johannes Schindelin wrote: > On Tue, 17 Jun 2008, Junio C Hamano wrote: > > > No, neither --theirs nor --ours option exists in your version of git. > > But here is a patch to add it to git-merge-file. > > Looks good, thanks! Just to be safe, this should be accompanied by tet > cases. But I did not see anything wrong with the patch. Thinking about this again, there could be a problem: in case of complex merges, it is possible that the sides are switched around for an intermediate merge. IOW you'd expect it to take "theirs", but it really takes "ours". Hrm. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-18 15:28 ` Johannes Schindelin @ 2008-06-18 16:31 ` Junio C Hamano 2008-06-18 19:29 ` Johannes Schindelin 2008-06-20 7:38 ` [PATCH 1/2] git-merge-file --ours, --theirs Junio C Hamano 0 siblings, 2 replies; 23+ messages in thread From: Junio C Hamano @ 2008-06-18 16:31 UTC (permalink / raw) To: Johannes Schindelin Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > Thinking about this again, there could be a problem: in case of complex > merges, it is possible that the sides are switched around for an > intermediate merge. IOW you'd expect it to take "theirs", but it really > takes "ours". Are you thinking about using this in merge-recursive? I do not think there is any reason to use this during intermediate merges done inside merge-recursive. The point of recursive merge is to create a neutral intermediate merge result, with conflicts and all. Do this only during the final round and you are fine (for some definition of "fine" --- I still have not heard a convincing argument as to why it is even a good thing to be able to take one side for only parts that did conflict, while taking the change from the other side in places that did not). ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-18 16:31 ` Junio C Hamano @ 2008-06-18 19:29 ` Johannes Schindelin 2008-06-20 7:38 ` [PATCH 1/2] git-merge-file --ours, --theirs Junio C Hamano 1 sibling, 0 replies; 23+ messages in thread From: Johannes Schindelin @ 2008-06-18 19:29 UTC (permalink / raw) To: Junio C Hamano; +Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Hi, On Wed, 18 Jun 2008, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > > > Thinking about this again, there could be a problem: in case of complex > > merges, it is possible that the sides are switched around for an > > intermediate merge. IOW you'd expect it to take "theirs", but it really > > takes "ours". > > Are you thinking about using this in merge-recursive? Indeed I was. > I do not think there is any reason to use this during intermediate > merges done inside merge-recursive. That is right, but for some stupid reason I did not realize that git-merge-file is not even called by merge-recursive. So the accompanying patch for merge-recursive would use the --theirs or --ours logic only in the !index_only case, i.e. the final merge. And I guess we'd have similar logic as for merge-subtree, introducing merge-recursive-ours and merge-recursive-theirs. Very nice. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/2] git-merge-file --ours, --theirs 2008-06-18 16:31 ` Junio C Hamano 2008-06-18 19:29 ` Johannes Schindelin @ 2008-06-20 7:38 ` Junio C Hamano 2008-06-20 7:48 ` [PATCH 2/2] git-merge-recursive-{ours,theirs} Junio C Hamano 1 sibling, 1 reply; 23+ messages in thread From: Junio C Hamano @ 2008-06-20 7:38 UTC (permalink / raw) To: Johannes Schindelin Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Often people want their conflicting merges autoresolved by favouring upstream changes (or their own --- it's the same thing), and hinted to run "git diff --name-only | xargs git checkout MERGE_HEAD --". This is essentially to accept automerge results for the paths that are fully resolved automatically while taking their version of the file in full for paths that have conflicts. This is problematic on two counts. One problem is that this is not exactly what these people want. They usually want to salvage as much automerge result as possible. In particular, they want to keep autoresolved parts in conflicting paths, as well as the paths that are fully autoresolved. This patch teaches two new modes of operation to the lowest-lever merge machinery, xdl_merge(). Instead of leaving the conflicted lines from both sides enclosed in <<<, ===, and >>> markers, you can tell the conflicts to be resolved favouring your side or their side of changes. A larger problem is that this tends to encourage a bad workflow by allowing them to record such a mixed up half-merge result as a full commit without auditing. This commit does not tackle this latter issue. In git, we usually give long enough rope to users with strange wishes as long as the risky features is not on by default. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- * Essentially the same patch but with documentation. Documentation/git-merge-file.txt | 12 ++++++++++-- builtin-merge-file.c | 10 ++++++++-- xdiff/xdiff.h | 8 +++++++- xdiff/xmerge.c | 24 ++++++++++++++++-------- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt index 149f131..87e07d3 100644 --- a/Documentation/git-merge-file.txt +++ b/Documentation/git-merge-file.txt @@ -10,7 +10,8 @@ SYNOPSIS -------- [verse] 'git-merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]] - [-p|--stdout] [-q|--quiet] <current-file> <base-file> <other-file> + [--ours|--theirs] [-p|--stdout] [-q|--quiet] + <current-file> <base-file> <other-file> DESCRIPTION @@ -34,7 +35,9 @@ normally outputs a warning and brackets the conflict with <<<<<<< and >>>>>>> B If there are conflicts, the user should edit the result and delete one of -the alternatives. +the alternatives. When `--ours` or `--theirs` option is in effect, however, +these conflicts are resolved favouring lines from `<current-file>` or +lines from `<other-file>` respectively. The exit value of this program is negative on error, and the number of conflicts otherwise. If the merge was clean, the exit value is 0. @@ -62,6 +65,11 @@ OPTIONS -q:: Quiet; do not warn about conflicts. +--ours:: +--theirs:: + Instead of leaving conflicts in the file, resolve conflicts + favouring our (or their) side of the lines. + EXAMPLES -------- diff --git a/builtin-merge-file.c b/builtin-merge-file.c index 3605960..7d4ca8c 100644 --- a/builtin-merge-file.c +++ b/builtin-merge-file.c @@ -4,7 +4,7 @@ #include "xdiff-interface.h" static const char merge_file_usage[] = -"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"; +"git merge-file [-p | --stdout] [-q | --quiet] [--ours|--theirs] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"; int cmd_merge_file(int argc, const char **argv, const char *prefix) { @@ -13,6 +13,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) mmbuffer_t result = {NULL, 0}; xpparam_t xpp = {XDF_NEED_MINIMAL}; int ret = 0, i = 0, to_stdout = 0; + int flags, favor = 0; while (argc > 4) { if (!strcmp(argv[1], "-L") && i < 3) { @@ -25,6 +26,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--quiet")) freopen("/dev/null", "w", stderr); + else if (!strcmp(argv[1], "--ours")) + favor = XDL_MERGE_FAVOR_OURS; + else if (!strcmp(argv[1], "--theirs")) + favor = XDL_MERGE_FAVOR_THEIRS; else usage(merge_file_usage); argc--; @@ -45,8 +50,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) argv[i + 1]); } + flags = XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS_ALNUM, favor); ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2], - &xpp, XDL_MERGE_ZEALOUS_ALNUM, &result); + &xpp, flags, &result); for (i = 0; i < 3; i++) free(mmfs[i].ptr); diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 413082e..d40cf21 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -99,9 +99,15 @@ long xdl_mmfile_size(mmfile_t *mmf); int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); +#define XDL_MERGE_FAVOR_OURS 1 +#define XDL_MERGE_FAVOR_THEIRS 2 +#define XDL_MERGE_FAVOR(flag) (((flag)>>4) & 03) +#define XDL_MERGE_LEVEL(flag) ((flag) & 07) +#define XDL_MERGE_FLAGS(level,flag) ((level) | ((flag)<<4)) + int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, mmfile_t *mf2, const char *name2, - xpparam_t const *xpp, int level, mmbuffer_t *result); + xpparam_t const *xpp, int flag, mmbuffer_t *result); #ifdef __cplusplus } diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 82b3573..88c29ae 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -114,7 +114,9 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) } static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, - xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest) + xdfenv_t *xe2, const char *name2, + int favor, + xdmerge_t *m, char *dest) { const int marker_size = 7; int marker1_size = (name1 ? strlen(name1) + 1 : 0); @@ -124,6 +126,9 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, int size, i1, j; for (size = i1 = 0; m; m = m->next) { + if (favor && !m->mode) + m->mode = favor; + if (m->mode == 0) { size += xdl_recs_copy(xe1, i1, m->i1 - i1, 0, dest ? dest + size : NULL); @@ -322,8 +327,9 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m, * returns < 0 on error, == 0 for no conflicts, else number of conflicts */ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1, - xdfenv_t *xe2, xdchange_t *xscr2, const char *name2, - int level, xpparam_t const *xpp, mmbuffer_t *result) { + xdfenv_t *xe2, xdchange_t *xscr2, const char *name2, + int level, int favor, + xpparam_t const *xpp, mmbuffer_t *result) { xdmerge_t *changes, *c; int i1, i2, chg1, chg2; @@ -430,25 +436,27 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1, /* output */ if (result) { int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2, - changes, NULL); + favor, changes, NULL); result->ptr = xdl_malloc(size); if (!result->ptr) { xdl_cleanup_merge(changes); return -1; } result->size = size; - xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes, - result->ptr); + xdl_fill_merge_buffer(xe1, name1, xe2, name2, + favor, changes, result->ptr); } return xdl_cleanup_merge(changes); } int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, mmfile_t *mf2, const char *name2, - xpparam_t const *xpp, int level, mmbuffer_t *result) { + xpparam_t const *xpp, int flag, mmbuffer_t *result) { xdchange_t *xscr1, *xscr2; xdfenv_t xe1, xe2; int status; + int level = XDL_MERGE_LEVEL(flag); + int favor = XDL_MERGE_FAVOR(flag); result->ptr = NULL; result->size = 0; @@ -482,7 +490,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, } else { status = xdl_do_merge(&xe1, xscr1, name1, &xe2, xscr2, name2, - level, xpp, result); + level, favor, xpp, result); } xdl_free_script(xscr1); xdl_free_script(xscr2); -- 1.5.6.6.gd3e97 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-20 7:38 ` [PATCH 1/2] git-merge-file --ours, --theirs Junio C Hamano @ 2008-06-20 7:48 ` Junio C Hamano 2008-06-20 12:58 ` Johannes Schindelin 0 siblings, 1 reply; 23+ messages in thread From: Junio C Hamano @ 2008-06-20 7:48 UTC (permalink / raw) To: Johannes Schindelin Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git This uses the low-level mechanism for "ours" and "theirs" autoresolution introduced by the previous commit to introduce two additional merge strategies, merge-recursive-ours and merge-recursive-theirs. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- Makefile | 3 ++ builtin-merge-recursive.c | 37 ++++++++++++++++++++++++--- git-merge.sh | 3 +- git.c | 2 + ll-merge.c | 24 +++++++++++------ ll-merge.h | 4 ++- t/t6034-merge-ours-theirs.sh | 56 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 114 insertions(+), 15 deletions(-) create mode 100755 t/t6034-merge-ours-theirs.sh diff --git a/Makefile b/Makefile index b003e3e..82d2892 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,8 @@ BUILT_INS += git-format-patch$X BUILT_INS += git-fsck-objects$X BUILT_INS += git-get-tar-commit-id$X BUILT_INS += git-init$X +BUILT_INS += git-merge-recursive-ours$X +BUILT_INS += git-merge-recursive-theirs$X BUILT_INS += git-merge-subtree$X BUILT_INS += git-peek-remote$X BUILT_INS += git-repo-config$X @@ -1381,6 +1383,7 @@ check-docs:: do \ case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ + git-merge-recursive-ours | git-merge-recursive-theirs | \ git-merge-resolve | git-merge-stupid | git-merge-subtree | \ git-fsck-objects | git-init-db | \ git-?*--?* ) continue ;; \ diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 4aa28a1..a355e7a 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -20,7 +20,11 @@ #include "attr.h" #include "merge-recursive.h" -static int subtree_merge; +static enum { + MERGE_RECURSIVE_SUBTREE = 1, + MERGE_RECURSIVE_OURS, + MERGE_RECURSIVE_THEIRS, +} merge_recursive_variants; static struct tree *shift_tree_object(struct tree *one, struct tree *two) { @@ -642,6 +646,7 @@ static int merge_3way(mmbuffer_t *result_buf, mmfile_t orig, src1, src2; char *name1, *name2; int merge_status; + int flag, favor; name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); @@ -650,9 +655,26 @@ static int merge_3way(mmbuffer_t *result_buf, fill_mm(a->sha1, &src1); fill_mm(b->sha1, &src2); + if (index_only) + favor = 0; + else { + switch (merge_recursive_variants) { + case MERGE_RECURSIVE_OURS: + favor = XDL_MERGE_FAVOR_OURS; + break; + case MERGE_RECURSIVE_THEIRS: + favor = XDL_MERGE_FAVOR_THEIRS; + break; + default: + favor = 0; + break; + } + } + flag = LL_MERGE_FLAGS(index_only, favor); + merge_status = ll_merge(result_buf, a->path, &orig, &src1, name1, &src2, name2, - index_only); + flag); free(name1); free(name2); @@ -1171,7 +1193,7 @@ int merge_trees(struct tree *head, { int code, clean; - if (subtree_merge) { + if (merge_recursive_variants == MERGE_RECURSIVE_SUBTREE) { merge = shift_tree_object(head, merge); common = shift_tree_object(head, common); } @@ -1379,11 +1401,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; + merge_recursive_variants = 0; if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) - subtree_merge = 1; + merge_recursive_variants = MERGE_RECURSIVE_SUBTREE; + else if (5 < namelen && + !strcmp(argv[0] + namelen - 5, "-ours")) + merge_recursive_variants = MERGE_RECURSIVE_OURS; + else if (7 < namelen && + !strcmp(argv[0] + namelen - 7, "-theirs")) + merge_recursive_variants = MERGE_RECURSIVE_THEIRS; } git_config(merge_config, NULL); diff --git a/git-merge.sh b/git-merge.sh index 8026ccf..39b5cd9 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -31,10 +31,11 @@ LF=' ' all_strategies='recur recursive octopus resolve stupid ours subtree' +all_strategies="$all_strategies recursive-ours recursive-theirs" default_twohead_strategies='recursive' default_octopus_strategies='octopus' no_fast_forward_strategies='subtree ours' -no_trivial_strategies='recursive recur subtree ours' +no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs' use_strategies= allow_fast_forward=t diff --git a/git.c b/git.c index 59f0fcc..44cb8eb 100644 --- a/git.c +++ b/git.c @@ -328,6 +328,8 @@ static void handle_internal_command(int argc, const char **argv) { "merge-file", cmd_merge_file }, { "merge-ours", cmd_merge_ours, RUN_SETUP }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, + { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, + { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE }, { "name-rev", cmd_name_rev, RUN_SETUP }, diff --git a/ll-merge.c b/ll-merge.c index 9837c84..c6a05bf 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -19,7 +19,7 @@ typedef int (*ll_merge_fn)(const struct ll_merge_driver *, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor); + int flag); struct ll_merge_driver { const char *name; @@ -39,13 +39,15 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { /* * The tentative merge result is "ours" for the final round, * or common ancestor for an internal merge. Still return * "conflicted merge" status. */ + int virtual_ancestor = flag & 01; + mmfile_t *stolen = virtual_ancestor ? orig : src1; result->ptr = stolen->ptr; @@ -60,9 +62,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { xpparam_t xpp; + int favor = ((flag)>>1) & 03; if (buffer_is_binary(orig->ptr, orig->size) || buffer_is_binary(src1->ptr, src1->size) || @@ -73,14 +76,15 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, path_unused, orig, src1, name1, src2, name2, - virtual_ancestor); + flag); } memset(&xpp, 0, sizeof(xpp)); return xdl_merge(orig, src1, name1, src2, name2, - &xpp, XDL_MERGE_ZEALOUS, + &xpp, + XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, favor), result); } @@ -90,11 +94,12 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { char *src, *dst; long size; const int marker_size = 7; + int virtual_ancestor = flag & 01; int status = ll_xdl_merge(drv_unused, result, path_unused, orig, src1, NULL, src2, NULL, @@ -158,7 +163,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { char temp[3][50]; char cmdbuf[2048]; @@ -362,10 +367,11 @@ int ll_merge(mmbuffer_t *result_buf, mmfile_t *ancestor, mmfile_t *ours, const char *our_label, mmfile_t *theirs, const char *their_label, - int virtual_ancestor) + int flag) { const char *ll_driver_name; const struct ll_merge_driver *driver; + int virtual_ancestor = flag & 01; ll_driver_name = git_path_check_merge(path); driver = find_ll_merge_driver(ll_driver_name); @@ -375,5 +381,5 @@ int ll_merge(mmbuffer_t *result_buf, return driver->fn(driver, result_buf, path, ancestor, ours, our_label, - theirs, their_label, virtual_ancestor); + theirs, their_label, flag); } diff --git a/ll-merge.h b/ll-merge.h index 5388422..5daef58 100644 --- a/ll-merge.h +++ b/ll-merge.h @@ -5,11 +5,13 @@ #ifndef LL_MERGE_H #define LL_MERGE_H +#define LL_MERGE_FLAGS(virtual_ancestor,favor) ((!!(virtual_ancestor)) | ((favor)<<1)) + int ll_merge(mmbuffer_t *result_buf, const char *path, mmfile_t *ancestor, mmfile_t *ours, const char *our_label, mmfile_t *theirs, const char *their_label, - int virtual_ancestor); + int flag); #endif diff --git a/t/t6034-merge-ours-theirs.sh b/t/t6034-merge-ours-theirs.sh new file mode 100755 index 0000000..56a9247 --- /dev/null +++ b/t/t6034-merge-ours-theirs.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +test_description='Merge-recursive ours and theirs variants' +. ./test-lib.sh + +test_expect_success setup ' + for i in 1 2 3 4 5 6 7 8 9 + do + echo "$i" + done >file && + git add file && + cp file elif && + git commit -m initial && + + sed -e "s/1/one/" -e "s/9/nine/" >file <elif && + git commit -a -m ours && + + git checkout -b side HEAD^ && + + sed -e "s/9/nueve/" >file <elif && + git commit -a -m theirs && + + git checkout master^0 +' + +test_expect_success 'plain recursive - should conflict' ' + git reset --hard master && + test_must_fail git merge -s recursive side && + grep nine file && + grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_expect_success 'recursive favouring theirs' ' + git reset --hard master && + git merge -s recursive-theirs side && + ! grep nine file && + grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_expect_success 'recursive favouring ours' ' + git reset --hard master && + git merge -s recursive-ours side && + grep nine file && + ! grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_done -- 1.5.6.6.gd3e97 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-20 7:48 ` [PATCH 2/2] git-merge-recursive-{ours,theirs} Junio C Hamano @ 2008-06-20 12:58 ` Johannes Schindelin 2008-06-21 9:46 ` Junio C Hamano 0 siblings, 1 reply; 23+ messages in thread From: Johannes Schindelin @ 2008-06-20 12:58 UTC (permalink / raw) To: Junio C Hamano; +Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Hi, On Fri, 20 Jun 2008, Junio C Hamano wrote: > diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c > index 4aa28a1..a355e7a 100644 > --- a/builtin-merge-recursive.c > +++ b/builtin-merge-recursive.c > @@ -650,9 +655,26 @@ static int merge_3way(mmbuffer_t *result_buf, > fill_mm(a->sha1, &src1); > fill_mm(b->sha1, &src2); > > + if (index_only) > + favor = 0; > + else { > + switch (merge_recursive_variants) { > + case MERGE_RECURSIVE_OURS: > + favor = XDL_MERGE_FAVOR_OURS; > + break; > + case MERGE_RECURSIVE_THEIRS: > + favor = XDL_MERGE_FAVOR_THEIRS; > + break; > + default: > + favor = 0; > + break; > + } Hrm. I would have preferred something like this: if (!index_only && merge_recursive_variants == MERGE_RECURSIVE_OURS) favor = XDL_MERGE_FAVOR_OURS; if (!index_only && merge_recursive_variants == MERGE_RECURSIVE_THEIRS) favor = XDL_MERGE_FAVOR_THEIRS; else favor = 0; > + } > + flag = LL_MERGE_FLAGS(index_only, favor); > + > merge_status = ll_merge(result_buf, a->path, &orig, > &src1, name1, &src2, name2, > - index_only); > + flag); Sorry, but in my opinion this flag mangling makes the whole code uglier. Why not just add another parameter? Or if you are really concerned about future enhancements to ll_merge(), use a struct. > @@ -1379,11 +1401,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) > struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); > int index_fd; > > + merge_recursive_variants = 0; > if (argv[0]) { > int namelen = strlen(argv[0]); > if (8 < namelen && > !strcmp(argv[0] + namelen - 8, "-subtree")) > - subtree_merge = 1; > + merge_recursive_variants = MERGE_RECURSIVE_SUBTREE; > + else if (5 < namelen && > + !strcmp(argv[0] + namelen - 5, "-ours")) > + merge_recursive_variants = MERGE_RECURSIVE_OURS; > + else if (7 < namelen && > + !strcmp(argv[0] + namelen - 7, "-theirs")) > + merge_recursive_variants = MERGE_RECURSIVE_THEIRS; This just cries out loud for a new function suffixcmp(). I will not say anything about the long lines in git-merge.sh, since I fully expect builtin-merge to happen Real Soon Now. Anyhow, your comments about this driving the wrong workflow still apply. Maybe we want to display them really, really prominently in Documentation/merge-strategies.txt. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-20 12:58 ` Johannes Schindelin @ 2008-06-21 9:46 ` Junio C Hamano 2008-06-21 16:29 ` Johannes Schindelin 2008-06-21 16:56 ` Jakub Narebski 0 siblings, 2 replies; 23+ messages in thread From: Junio C Hamano @ 2008-06-21 9:46 UTC (permalink / raw) To: Johannes Schindelin Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: >> @@ -1379,11 +1401,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) >> struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); >> int index_fd; >> >> + merge_recursive_variants = 0; >> if (argv[0]) { >> int namelen = strlen(argv[0]); >> if (8 < namelen && >> !strcmp(argv[0] + namelen - 8, "-subtree")) >> - subtree_merge = 1; >> + merge_recursive_variants = MERGE_RECURSIVE_SUBTREE; >> + else if (5 < namelen && >> + !strcmp(argv[0] + namelen - 5, "-ours")) >> + merge_recursive_variants = MERGE_RECURSIVE_OURS; >> + else if (7 < namelen && >> + !strcmp(argv[0] + namelen - 7, "-theirs")) >> + merge_recursive_variants = MERGE_RECURSIVE_THEIRS; > > This just cries out loud for a new function suffixcmp(). Actually, I think "git-merge-recursive-theirs" is a mistake. We should bite the bullet and give "git-merge" an ability to pass backend specific parameters to "git-merge-recursive". The new convention could be that anything that begins with -X is passed to the backend. E.g. git merge -Xfavor=theirs foo git merge -Xsubtree=/=gitk-git paulus As you noticed already, subtree is just a funny optional behaviour attached to recursive, so are theirs and ours. The above two would invoke git-merge-recursive like so: git merge-recursive -Xfavor=theirs <base> -- HEAD MERGE_HEAD git merge-recursive -Xsubtree=/=gitk-git <base> -- HEAD MERGE_HEAD We could even mix these two if we are ambitious. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-21 9:46 ` Junio C Hamano @ 2008-06-21 16:29 ` Johannes Schindelin 2008-06-21 16:56 ` Jakub Narebski 1 sibling, 0 replies; 23+ messages in thread From: Johannes Schindelin @ 2008-06-21 16:29 UTC (permalink / raw) To: Junio C Hamano; +Cc: geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Hi, On Sat, 21 Jun 2008, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > > >> @@ -1379,11 +1401,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) > >> struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); > >> int index_fd; > >> > >> + merge_recursive_variants = 0; > >> if (argv[0]) { > >> int namelen = strlen(argv[0]); > >> if (8 < namelen && > >> !strcmp(argv[0] + namelen - 8, "-subtree")) > >> - subtree_merge = 1; > >> + merge_recursive_variants = MERGE_RECURSIVE_SUBTREE; > >> + else if (5 < namelen && > >> + !strcmp(argv[0] + namelen - 5, "-ours")) > >> + merge_recursive_variants = MERGE_RECURSIVE_OURS; > >> + else if (7 < namelen && > >> + !strcmp(argv[0] + namelen - 7, "-theirs")) > >> + merge_recursive_variants = MERGE_RECURSIVE_THEIRS; > > > > This just cries out loud for a new function suffixcmp(). > > Actually, I think "git-merge-recursive-theirs" is a mistake. We should > bite the bullet and give "git-merge" an ability to pass backend specific > parameters to "git-merge-recursive". Fair enough. > The new convention could be that anything that begins with -X is passed > to the backend. > > E.g. > > git merge -Xfavor=theirs foo > git merge -Xsubtree=/=gitk-git paulus > > As you noticed already, subtree is just a funny optional behaviour > attached to recursive, so are theirs and ours. The above two would invoke > git-merge-recursive like so: > > git merge-recursive -Xfavor=theirs <base> -- HEAD MERGE_HEAD > git merge-recursive -Xsubtree=/=gitk-git <base> -- HEAD MERGE_HEAD > > We could even mix these two if we are ambitious. Looks fine to me. And much cleaner than the hardlinking. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-21 9:46 ` Junio C Hamano 2008-06-21 16:29 ` Johannes Schindelin @ 2008-06-21 16:56 ` Jakub Narebski 1 sibling, 0 replies; 23+ messages in thread From: Jakub Narebski @ 2008-06-21 16:56 UTC (permalink / raw) To: Junio C Hamano Cc: Johannes Schindelin, geoffrey.russell, sverre, Johannes Sixt, Miklos Vajna, git Junio C Hamano <gitster@pobox.com> writes: > Actually, I think "git-merge-recursive-theirs" is a mistake. We should > bite the bullet and give "git-merge" an ability to pass backend specific > parameters to "git-merge-recursive". The new convention could be that > anything that begins with -X is passed to the backend. > > E.g. > > git merge -Xfavor=theirs foo > git merge -Xsubtree=/=gitk-git paulus Gaaah... only after reading it for third time I see that it isn't some funky "=/=" symbol, but subtree with grafing '/' in one side to 'gitk-git' subdirectory in other side. -- Jakub Narebski Poland ShadeHawk on #git ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-16 22:21 ` Sverre Rabbelier 2008-06-16 22:45 ` Geoff Russell @ 2008-06-17 6:16 ` Johannes Sixt 2008-06-17 8:53 ` Sverre Rabbelier 1 sibling, 1 reply; 23+ messages in thread From: Johannes Sixt @ 2008-06-17 6:16 UTC (permalink / raw) To: sverre; +Cc: Miklos Vajna, Geoff Russell, git Sverre Rabbelier schrieb: > On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote: >> The solution depends on whether *all* files in B should be taken, or only >> those files in B where there's a merge conflict. I don't know an easy way >> to do the former, but the latter I'd do like this: >> >> $ git diff --name-only | xargs git checkout B -- > > Wouldn't something similar work but do a 'git ls-files' and filter it > on files that have a merge conflict? Well, you could 'git ls-files --unmerged', but that prints the whole index entry, not just the name, and then you need a more complicated pipeline. -- Hannes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-17 6:16 ` Guided merge with override Johannes Sixt @ 2008-06-17 8:53 ` Sverre Rabbelier 2008-06-17 9:48 ` Johannes Schindelin 0 siblings, 1 reply; 23+ messages in thread From: Sverre Rabbelier @ 2008-06-17 8:53 UTC (permalink / raw) To: Johannes Sixt; +Cc: Miklos Vajna, Geoff Russell, git On Tue, Jun 17, 2008 at 8:16 AM, Johannes Sixt <j.sixt@viscovery.net> wrote: > Sverre Rabbelier schrieb: >> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@viscovery.net> wrote: >>> The solution depends on whether *all* files in B should be taken, or only >>> those files in B where there's a merge conflict. I don't know an easy way >>> to do the former, but the latter I'd do like this: >>> >>> $ git diff --name-only | xargs git checkout B -- >> >> Wouldn't something similar work but do a 'git ls-files' and filter it >> on files that have a merge conflict? > > Well, you could 'git ls-files --unmerged', but that prints the whole index > entry, not just the name, and then you need a more complicated pipeline. How about 'git ls-files -t | grep "^M " | xargs git checkout B --', that would list all files that are unmerged and check them out? -- Cheers, Sverre Rabbelier ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-17 8:53 ` Sverre Rabbelier @ 2008-06-17 9:48 ` Johannes Schindelin 2008-06-17 9:53 ` Sverre Rabbelier 0 siblings, 1 reply; 23+ messages in thread From: Johannes Schindelin @ 2008-06-17 9:48 UTC (permalink / raw) To: sverre; +Cc: Johannes Sixt, Miklos Vajna, Geoff Russell, git Hi, On Tue, 17 Jun 2008, Sverre Rabbelier wrote: > How about 'git ls-files -t | grep "^M " | xargs git checkout B --', You probably meant 'sed -n "s/^M //p"' instead of 'grep "^M"', right? Of course, I think that a better way would be to ask "git diff --name-only --diff-filter=U". Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-17 9:48 ` Johannes Schindelin @ 2008-06-17 9:53 ` Sverre Rabbelier 2008-06-17 10:17 ` Johannes Schindelin 0 siblings, 1 reply; 23+ messages in thread From: Sverre Rabbelier @ 2008-06-17 9:53 UTC (permalink / raw) To: Johannes Schindelin; +Cc: Johannes Sixt, Miklos Vajna, Geoff Russell, git On Tue, Jun 17, 2008 at 11:48 AM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote: > On Tue, 17 Jun 2008, Sverre Rabbelier wrote: >> How about 'git ls-files -t | grep "^M " | xargs git checkout B --', > > You probably meant 'sed -n "s/^M //p"' instead of 'grep "^M"', right? Whoops, yes, that would be a lot better :P. > Of course, I think that a better way would be to ask "git diff > --name-only --diff-filter=U". Hmmm, not having an unfinished merge at hand, would that require the sed on top too? -- Cheers, Sverre Rabbelier ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Guided merge with override 2008-06-17 9:53 ` Sverre Rabbelier @ 2008-06-17 10:17 ` Johannes Schindelin 0 siblings, 0 replies; 23+ messages in thread From: Johannes Schindelin @ 2008-06-17 10:17 UTC (permalink / raw) To: sverre; +Cc: Johannes Sixt, Miklos Vajna, Geoff Russell, git Hi, On Tue, 17 Jun 2008, Sverre Rabbelier wrote: > On Tue, Jun 17, 2008 at 11:48 AM, Johannes Schindelin > <Johannes.Schindelin@gmx.de> wrote: > > > Of course, I think that a better way would be to ask "git diff > > --name-only --diff-filter=U". > > Hmmm, not having an unfinished merge at hand, would that require the > sed on top too? Nope. The "--name-only" says it will print only the name. Ciao, Dscho ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/2] jc/merge-theirs, rebased on top of mv/merge-in-c
@ 2008-06-23 12:45 Miklos Vajna
2008-06-23 12:45 ` [PATCH 2/2] git-merge-recursive-{ours,theirs} Miklos Vajna
0 siblings, 1 reply; 23+ messages in thread
From: Miklos Vajna @ 2008-06-23 12:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
On Mon, Jun 23, 2008 at 12:15:35AM -0700, Junio C Hamano <gitster@pobox.com> wrote:
> Currently tip of 'pu' is broken and does not pass tests, as j6t/mingw
> has interaction with dr/ceiling and jc/merge-theirs has interaction
> with mv/merge-in-c.
Here is jc/merge-theirs, on top of mv/merge-in-c. Now all tests pass
here if I merge both to master.
To avoid unnecessary traffic, I do not send e0aafb4 ([PATCH 1/2]
git-merge-file --ours, --theirs"), as that is unchanged.
Junio C Hamano (2):
git-merge-file --ours, --theirs
git-merge-recursive-{ours,theirs}
Documentation/git-merge-file.txt | 12 +++++++-
Makefile | 3 ++
builtin-merge-file.c | 10 +++++-
builtin-merge-recursive.c | 37 ++++++++++++++++++++++---
builtin-merge.c | 2 +
git.c | 2 +
ll-merge.c | 24 ++++++++++------
ll-merge.h | 4 ++-
t/t6034-merge-ours-theirs.sh | 56 ++++++++++++++++++++++++++++++++++++++
xdiff/xdiff.h | 8 +++++-
xdiff/xmerge.c | 24 +++++++++++-----
11 files changed, 155 insertions(+), 27 deletions(-)
create mode 100755 t/t6034-merge-ours-theirs.sh
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 2/2] git-merge-recursive-{ours,theirs} 2008-06-23 12:45 [PATCH 0/2] jc/merge-theirs, rebased on top of mv/merge-in-c Miklos Vajna @ 2008-06-23 12:45 ` Miklos Vajna 0 siblings, 0 replies; 23+ messages in thread From: Miklos Vajna @ 2008-06-23 12:45 UTC (permalink / raw) To: git; +Cc: Junio C Hamano From: Junio C Hamano <gitster@pobox.com> This uses the low-level mechanism for "ours" and "theirs" autoresolution introduced by the previous commit to introduce two additional merge strategies, merge-recursive-ours and merge-recursive-theirs. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- The patch is the same, but I removed modifications to git-merge.sh and added them to builtin-merge.c. Makefile | 3 ++ builtin-merge-recursive.c | 37 ++++++++++++++++++++++++--- builtin-merge.c | 2 + git.c | 2 + ll-merge.c | 24 +++++++++++------ ll-merge.h | 4 ++- t/t6034-merge-ours-theirs.sh | 56 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 114 insertions(+), 14 deletions(-) create mode 100755 t/t6034-merge-ours-theirs.sh diff --git a/Makefile b/Makefile index 3d8c3d2..4e354fc 100644 --- a/Makefile +++ b/Makefile @@ -303,6 +303,8 @@ BUILT_INS += git-format-patch$X BUILT_INS += git-fsck-objects$X BUILT_INS += git-get-tar-commit-id$X BUILT_INS += git-init$X +BUILT_INS += git-merge-recursive-ours$X +BUILT_INS += git-merge-recursive-theirs$X BUILT_INS += git-merge-subtree$X BUILT_INS += git-peek-remote$X BUILT_INS += git-repo-config$X @@ -1381,6 +1383,7 @@ check-docs:: do \ case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ + git-merge-recursive-ours | git-merge-recursive-theirs | \ git-merge-resolve | git-merge-stupid | git-merge-subtree | \ git-fsck-objects | git-init-db | \ git-?*--?* ) continue ;; \ diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 98b09fb..c535596 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -20,7 +20,11 @@ #include "attr.h" #include "merge-recursive.h" -static int subtree_merge; +static enum { + MERGE_RECURSIVE_SUBTREE = 1, + MERGE_RECURSIVE_OURS, + MERGE_RECURSIVE_THEIRS, +} merge_recursive_variants; static struct tree *shift_tree_object(struct tree *one, struct tree *two) { @@ -634,6 +638,7 @@ static int merge_3way(mmbuffer_t *result_buf, mmfile_t orig, src1, src2; char *name1, *name2; int merge_status; + int flag, favor; name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); @@ -642,9 +647,26 @@ static int merge_3way(mmbuffer_t *result_buf, fill_mm(a->sha1, &src1); fill_mm(b->sha1, &src2); + if (index_only) + favor = 0; + else { + switch (merge_recursive_variants) { + case MERGE_RECURSIVE_OURS: + favor = XDL_MERGE_FAVOR_OURS; + break; + case MERGE_RECURSIVE_THEIRS: + favor = XDL_MERGE_FAVOR_THEIRS; + break; + default: + favor = 0; + break; + } + } + flag = LL_MERGE_FLAGS(index_only, favor); + merge_status = ll_merge(result_buf, a->path, &orig, &src1, name1, &src2, name2, - index_only); + flag); free(name1); free(name2); @@ -1163,7 +1185,7 @@ int merge_trees(struct tree *head, { int code, clean; - if (subtree_merge) { + if (merge_recursive_variants == MERGE_RECURSIVE_SUBTREE) { merge = shift_tree_object(head, merge); common = shift_tree_object(head, common); } @@ -1371,11 +1393,18 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; + merge_recursive_variants = 0; if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) - subtree_merge = 1; + merge_recursive_variants = MERGE_RECURSIVE_SUBTREE; + else if (5 < namelen && + !strcmp(argv[0] + namelen - 5, "-ours")) + merge_recursive_variants = MERGE_RECURSIVE_OURS; + else if (7 < namelen && + !strcmp(argv[0] + namelen - 7, "-theirs")) + merge_recursive_variants = MERGE_RECURSIVE_THEIRS; } git_config(merge_config, NULL); diff --git a/builtin-merge.c b/builtin-merge.c index dadde80..b7b1b71 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -52,6 +52,8 @@ static struct path_list_item strategy_items[] = { { "stupid", (void *)0 }, { "ours", (void *)(NO_FAST_FORWARD | NO_TRIVIAL) }, { "subtree", (void *)(NO_FAST_FORWARD | NO_TRIVIAL) }, + { "recursive-ours", (void *)NO_TRIVIAL }, + { "recursive-theirs", (void *)NO_TRIVIAL }, }; static struct path_list strategies = { strategy_items, ARRAY_SIZE(strategy_items), 0, 0 }; diff --git a/git.c b/git.c index 770aadd..f2a8ce5 100644 --- a/git.c +++ b/git.c @@ -276,6 +276,8 @@ static void handle_internal_command(int argc, const char **argv) { "merge-file", cmd_merge_file }, { "merge-ours", cmd_merge_ours, RUN_SETUP }, { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, + { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, + { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE }, { "name-rev", cmd_name_rev, RUN_SETUP }, diff --git a/ll-merge.c b/ll-merge.c index 9837c84..c6a05bf 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -19,7 +19,7 @@ typedef int (*ll_merge_fn)(const struct ll_merge_driver *, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor); + int flag); struct ll_merge_driver { const char *name; @@ -39,13 +39,15 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { /* * The tentative merge result is "ours" for the final round, * or common ancestor for an internal merge. Still return * "conflicted merge" status. */ + int virtual_ancestor = flag & 01; + mmfile_t *stolen = virtual_ancestor ? orig : src1; result->ptr = stolen->ptr; @@ -60,9 +62,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { xpparam_t xpp; + int favor = ((flag)>>1) & 03; if (buffer_is_binary(orig->ptr, orig->size) || buffer_is_binary(src1->ptr, src1->size) || @@ -73,14 +76,15 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, path_unused, orig, src1, name1, src2, name2, - virtual_ancestor); + flag); } memset(&xpp, 0, sizeof(xpp)); return xdl_merge(orig, src1, name1, src2, name2, - &xpp, XDL_MERGE_ZEALOUS, + &xpp, + XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, favor), result); } @@ -90,11 +94,12 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { char *src, *dst; long size; const int marker_size = 7; + int virtual_ancestor = flag & 01; int status = ll_xdl_merge(drv_unused, result, path_unused, orig, src1, NULL, src2, NULL, @@ -158,7 +163,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, mmfile_t *orig, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, - int virtual_ancestor) + int flag) { char temp[3][50]; char cmdbuf[2048]; @@ -362,10 +367,11 @@ int ll_merge(mmbuffer_t *result_buf, mmfile_t *ancestor, mmfile_t *ours, const char *our_label, mmfile_t *theirs, const char *their_label, - int virtual_ancestor) + int flag) { const char *ll_driver_name; const struct ll_merge_driver *driver; + int virtual_ancestor = flag & 01; ll_driver_name = git_path_check_merge(path); driver = find_ll_merge_driver(ll_driver_name); @@ -375,5 +381,5 @@ int ll_merge(mmbuffer_t *result_buf, return driver->fn(driver, result_buf, path, ancestor, ours, our_label, - theirs, their_label, virtual_ancestor); + theirs, their_label, flag); } diff --git a/ll-merge.h b/ll-merge.h index 5388422..5daef58 100644 --- a/ll-merge.h +++ b/ll-merge.h @@ -5,11 +5,13 @@ #ifndef LL_MERGE_H #define LL_MERGE_H +#define LL_MERGE_FLAGS(virtual_ancestor,favor) ((!!(virtual_ancestor)) | ((favor)<<1)) + int ll_merge(mmbuffer_t *result_buf, const char *path, mmfile_t *ancestor, mmfile_t *ours, const char *our_label, mmfile_t *theirs, const char *their_label, - int virtual_ancestor); + int flag); #endif diff --git a/t/t6034-merge-ours-theirs.sh b/t/t6034-merge-ours-theirs.sh new file mode 100755 index 0000000..56a9247 --- /dev/null +++ b/t/t6034-merge-ours-theirs.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +test_description='Merge-recursive ours and theirs variants' +. ./test-lib.sh + +test_expect_success setup ' + for i in 1 2 3 4 5 6 7 8 9 + do + echo "$i" + done >file && + git add file && + cp file elif && + git commit -m initial && + + sed -e "s/1/one/" -e "s/9/nine/" >file <elif && + git commit -a -m ours && + + git checkout -b side HEAD^ && + + sed -e "s/9/nueve/" >file <elif && + git commit -a -m theirs && + + git checkout master^0 +' + +test_expect_success 'plain recursive - should conflict' ' + git reset --hard master && + test_must_fail git merge -s recursive side && + grep nine file && + grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_expect_success 'recursive favouring theirs' ' + git reset --hard master && + git merge -s recursive-theirs side && + ! grep nine file && + grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_expect_success 'recursive favouring ours' ' + git reset --hard master && + git merge -s recursive-ours side && + grep nine file && + ! grep nueve file && + ! grep 9 file && + grep one file && + ! grep 1 file +' + +test_done -- 1.5.6 ^ permalink raw reply related [flat|nested] 23+ messages in thread
end of thread, other threads:[~2008-06-23 12:46 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-06-16 4:16 Guided merge with override Geoff Russell 2008-06-16 9:25 ` Miklos Vajna 2008-06-16 10:16 ` Johannes Sixt 2008-06-16 21:16 ` Miklos Vajna 2008-06-16 22:21 ` Sverre Rabbelier 2008-06-16 22:45 ` Geoff Russell 2008-06-17 20:04 ` Junio C Hamano 2008-06-18 15:19 ` Johannes Schindelin 2008-06-18 15:28 ` Johannes Schindelin 2008-06-18 16:31 ` Junio C Hamano 2008-06-18 19:29 ` Johannes Schindelin 2008-06-20 7:38 ` [PATCH 1/2] git-merge-file --ours, --theirs Junio C Hamano 2008-06-20 7:48 ` [PATCH 2/2] git-merge-recursive-{ours,theirs} Junio C Hamano 2008-06-20 12:58 ` Johannes Schindelin 2008-06-21 9:46 ` Junio C Hamano 2008-06-21 16:29 ` Johannes Schindelin 2008-06-21 16:56 ` Jakub Narebski 2008-06-17 6:16 ` Guided merge with override Johannes Sixt 2008-06-17 8:53 ` Sverre Rabbelier 2008-06-17 9:48 ` Johannes Schindelin 2008-06-17 9:53 ` Sverre Rabbelier 2008-06-17 10:17 ` Johannes Schindelin -- strict thread matches above, loose matches on Subject: below -- 2008-06-23 12:45 [PATCH 0/2] jc/merge-theirs, rebased on top of mv/merge-in-c Miklos Vajna 2008-06-23 12:45 ` [PATCH 2/2] git-merge-recursive-{ours,theirs} Miklos Vajna
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).