Re: Guided merge with override

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



"Geoff Russell" <geoffrey.russell@xxxxxxxxx> writes:

> Thanks everybody,
>
> On 6/17/08, Sverre Rabbelier <alturin@xxxxxxxxx> wrote:
>> On Mon, Jun 16, 2008 at 12:16 PM, Johannes Sixt <j.sixt@xxxxxxxxxxxxx> 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);
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux