Code

Merge branch 'bw/union-merge-refactor'
authorJunio C Hamano <gitster@pobox.com>
Sat, 20 Mar 2010 18:29:34 +0000 (11:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 20 Mar 2010 18:29:34 +0000 (11:29 -0700)
* bw/union-merge-refactor:
  merge-file: add option to select union merge favor
  merge-file: add option to specify the marker size
  refactor merge flags into xmparam_t
  make union merge an xdl merge favor

Documentation/git-merge-file.txt
builtin/merge-file.c
ll-merge.c
t/t6023-merge-file.sh
xdiff/xdiff.h
xdiff/xmerge.c

index 234269ae59234de67ea2cce42edec83cebc400be..f334d694e0160df91d197293e5b76cc0bfaac187 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
-       [--ours|--theirs] [-p|--stdout] [-q|--quiet]
+       [--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
        <current-file> <base-file> <other-file>
 
 
@@ -35,9 +35,10 @@ normally outputs a warning and brackets the conflict with lines containing
        >>>>>>> B
 
 If there are conflicts, the user should edit the result and delete one of
-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 alternatives.  When `--ours`, `--theirs`, or `--union` option is in effect,
+however, these conflicts are resolved favouring lines from `<current-file>`,
+lines from `<other-file>`, or lines from both respectively.  The length of the
+conflict markers can be given with the `--marker-size` option.
 
 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.
@@ -67,8 +68,9 @@ OPTIONS
 
 --ours::
 --theirs::
+--union::
        Instead of leaving conflicts in the file, resolve conflicts
-       favouring our (or their) side of the lines.
+       favouring our (or their or both) side of the lines.
 
 
 EXAMPLES
index 1e70073a7ed022675031706a8e9f8c57ff3aa2a9..69cc683332a04ddc6959fcef3d2853ccfb2860b8 100644 (file)
@@ -27,30 +27,35 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        mmbuffer_t result = {NULL, 0};
        xmparam_t xmp = {{XDF_NEED_MINIMAL}};
        int ret = 0, i = 0, to_stdout = 0;
-       int level = XDL_MERGE_ZEALOUS_ALNUM;
-       int style = 0, quiet = 0;
-       int favor = 0;
+       int quiet = 0;
        int nongit;
-
        struct option options[] = {
                OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
-               OPT_SET_INT(0, "diff3", &style, "use a diff3 based merge", XDL_MERGE_DIFF3),
-               OPT_SET_INT(0, "ours", &favor, "for conflicts, use our version",
+               OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
+               OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version",
                            XDL_MERGE_FAVOR_OURS),
-               OPT_SET_INT(0, "theirs", &favor, "for conflicts, use their version",
+               OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version",
                            XDL_MERGE_FAVOR_THEIRS),
+               OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version",
+                           XDL_MERGE_FAVOR_UNION),
+               OPT_INTEGER(0, "marker-size", &xmp.marker_size,
+                           "for conflicts, use this marker size"),
                OPT__QUIET(&quiet),
                OPT_CALLBACK('L', NULL, names, "name",
                             "set labels for file1/orig_file/file2", &label_cb),
                OPT_END(),
        };
 
+       xmp.level = XDL_MERGE_ZEALOUS_ALNUM;
+       xmp.style = 0;
+       xmp.favor = 0;
+
        prefix = setup_git_directory_gently(&nongit);
        if (!nongit) {
                /* Read the configuration file */
                git_config(git_xmerge_config, NULL);
                if (0 <= git_xmerge_style)
-                       style = git_xmerge_style;
+                       xmp.style = git_xmerge_style;
        }
 
        argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
@@ -73,7 +78,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        }
 
        ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
-                       &xmp, XDL_MERGE_FLAGS(level, style, favor), &result);
+                       &xmp, &result);
 
        for (i = 0; i < 3; i++)
                free(mmfs[i].ptr);
index 4c7f11ba84c67089dce7d725d87a4dd32a245c7f..82c7742e41f4645e7d6086bb277437a84ff4f03b 100644 (file)
@@ -63,8 +63,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        int flag, int marker_size)
 {
        xmparam_t xmp;
-       int style = 0;
-       int favor = (flag >> 1) & 03;
 
        if (buffer_is_binary(orig->ptr, orig->size) ||
            buffer_is_binary(src1->ptr, src1->size) ||
@@ -79,15 +77,13 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
        }
 
        memset(&xmp, 0, sizeof(xmp));
+       xmp.level = XDL_MERGE_ZEALOUS;
+       xmp.favor= (flag >> 1) & 03;
        if (git_xmerge_style >= 0)
-               style = git_xmerge_style;
+               xmp.style = git_xmerge_style;
        if (marker_size > 0)
                xmp.marker_size = marker_size;
-       return xdl_merge(orig,
-                        src1, name1,
-                        src2, name2,
-                        &xmp, XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, style, favor),
-                        result);
+       return xdl_merge(orig, src1, name1, src2, name2, &xmp, result);
 }
 
 static int ll_union_merge(const struct ll_merge_driver *drv_unused,
@@ -98,44 +94,11 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
                          mmfile_t *src2, const char *name2,
                          int flag, int marker_size)
 {
-       char *src, *dst;
-       long size;
-       int status, saved_style;
-
-       /* We have to force the RCS "merge" style */
-       saved_style = git_xmerge_style;
-       git_xmerge_style = 0;
-       status = ll_xdl_merge(drv_unused, result, path_unused,
-                             orig, src1, NULL, src2, NULL,
-                             flag, marker_size);
-       git_xmerge_style = saved_style;
-       if (status <= 0)
-               return status;
-       size = result->size;
-       src = dst = result->ptr;
-       while (size) {
-               char ch;
-               if ((marker_size < size) &&
-                   (*src == '<' || *src == '=' || *src == '>')) {
-                       int i;
-                       ch = *src;
-                       for (i = 0; i < marker_size; i++)
-                               if (src[i] != ch)
-                                       goto not_a_marker;
-                       if (src[marker_size] != '\n')
-                               goto not_a_marker;
-                       src += marker_size + 1;
-                       size -= marker_size + 1;
-                       continue;
-               }
-       not_a_marker:
-               do {
-                       ch = *src++;
-                       *dst++ = ch;
-                       size--;
-               } while (ch != '\n' && size);
-       }
-       result->size = dst - result->ptr;
+       /* Use union favor */
+       flag = (flag & 1) | (XDL_MERGE_FAVOR_UNION << 1);
+       return ll_xdl_merge(drv_unused, result, path_unused,
+                           orig, src1, NULL, src2, NULL,
+                           flag, marker_size);
        return 0;
 }
 
index d605024cf8d5375a2cd321e5541256c7fe23556a..5034dd1352c275beca4d5dae805cad6573a89aca 100755 (executable)
@@ -215,4 +215,41 @@ test_expect_success '"diff3 -m" style output (2)' '
        test_cmp expect actual
 '
 
+cat >expect <<\EOF
+Dominus regit me,
+<<<<<<<<<< new8.txt
+et nihil mihi deerit;
+
+
+
+
+In loco pascuae ibi me collocavit;
+super aquam refectionis educavit me.
+||||||||||
+et nihil mihi deerit.
+In loco pascuae ibi me collocavit,
+super aquam refectionis educavit me;
+==========
+et nihil mihi deerit,
+
+
+
+
+In loco pascuae ibi me collocavit --
+super aquam refectionis educavit me,
+>>>>>>>>>> new9.txt
+animam meam convertit,
+deduxit me super semitas jusitiae,
+propter nomen suum.
+Nam et si ambulavero in medio umbrae mortis,
+non timebo mala, quoniam TU mecum es:
+virga tua et baculus tuus ipsa me consolata sunt.
+EOF
+
+test_expect_success 'marker size' '
+       test_must_fail git merge-file -p --marker-size=10 \
+               new8.txt new5.txt new9.txt >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 3f6229edbeb21bb1ca0c423d88390f3b5a05b5a2..a71763ade835fd93ef291106298647408ada08e9 100644 (file)
@@ -56,17 +56,14 @@ extern "C" {
 #define XDL_MERGE_EAGER 1
 #define XDL_MERGE_ZEALOUS 2
 #define XDL_MERGE_ZEALOUS_ALNUM 3
-#define XDL_MERGE_LEVEL_MASK 0x0f
 
 /* merge favor modes */
 #define XDL_MERGE_FAVOR_OURS 1
 #define XDL_MERGE_FAVOR_THEIRS 2
-#define XDL_MERGE_FAVOR(flags) (((flags)>>4) & 3)
-#define XDL_MERGE_FLAGS(level, style, favor) ((level)|(style)|((favor)<<4))
+#define XDL_MERGE_FAVOR_UNION 3
 
 /* merge output styles */
-#define XDL_MERGE_DIFF3 0x8000
-#define XDL_MERGE_STYLE_MASK 0x8000
+#define XDL_MERGE_DIFF3 1
 
 typedef struct s_mmfile {
        char *ptr;
@@ -117,13 +114,16 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
 typedef struct s_xmparam {
        xpparam_t xpp;
        int marker_size;
+       int level;
+       int favor;
+       int style;
 } xmparam_t;
 
 #define DEFAULT_CONFLICT_MARKER_SIZE 7
 
 int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                mmfile_t *mf2, const char *name2,
-               xmparam_t const *xmp, int flags, mmbuffer_t *result);
+               xmparam_t const *xmp, mmbuffer_t *result);
 
 #ifdef __cplusplus
 }
index 8cbe45e6755487dbe3759398375a11d05f6d91bc..87cafa7021468d00a11c72dfdc1df05f1ede0fea 100644 (file)
@@ -28,6 +28,7 @@ typedef struct s_xdmerge {
         * 0 = conflict,
         * 1 = no conflict, take first,
         * 2 = no conflict, take second.
+        * 3 = no conflict, take both.
         */
        int mode;
        /*
@@ -230,14 +231,19 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                        size = fill_conflict_hunk(xe1, name1, xe2, name2,
                                                  size, i, style, m, dest,
                                                  marker_size);
-               else if (m->mode == 1)
-                       size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
+               else if (m->mode & 3) {
+                       /* Before conflicting part */
+                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
                                              dest ? dest + size : NULL);
-               else if (m->mode == 2)
-                       size += xdl_recs_copy(xe2, m->i2 - m->i1 + i,
-                                             m->i1 + m->chg2 - i, 0,
-                                             dest ? dest + size : NULL);
-               else
+                       /* Postimage from side #1 */
+                       if (m->mode & 1)
+                               size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
+                                                     dest ? dest + size : NULL);
+                       /* Postimage from side #2 */
+                       if (m->mode & 2)
+                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
+                                                     dest ? dest + size : NULL);
+               } else
                        continue;
                i = m->i1 + m->chg1;
        }
@@ -394,13 +400,13 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
  */
 static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
                xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
-               int flags, xmparam_t const *xmp, mmbuffer_t *result) {
+               xmparam_t const *xmp, mmbuffer_t *result) {
        xdmerge_t *changes, *c;
        xpparam_t const *xpp = &xmp->xpp;
        int i0, i1, i2, chg0, chg1, chg2;
-       int level = flags & XDL_MERGE_LEVEL_MASK;
-       int style = flags & XDL_MERGE_STYLE_MASK;
-       int favor = XDL_MERGE_FAVOR(flags);
+       int level = xmp->level;
+       int style = xmp->style;
+       int favor = xmp->favor;
 
        if (style == XDL_MERGE_DIFF3) {
                /*
@@ -550,7 +556,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
 
 int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                mmfile_t *mf2, const char *name2,
-               xmparam_t const *xmp, int flags, mmbuffer_t *result) {
+               xmparam_t const *xmp, mmbuffer_t *result) {
        xdchange_t *xscr1, *xscr2;
        xdfenv_t xe1, xe2;
        int status;
@@ -587,7 +593,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
        } else {
                status = xdl_do_merge(&xe1, xscr1, name1,
                                      &xe2, xscr2, name2,
-                                     flags, xmp, result);
+                                     xmp, result);
        }
        xdl_free_script(xscr1);
        xdl_free_script(xscr2);