Code

Merge branch 'jc/conflict-marker-size'
authorJunio C Hamano <gitster@pobox.com>
Thu, 21 Jan 2010 04:28:51 +0000 (20:28 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 21 Jan 2010 04:28:51 +0000 (20:28 -0800)
* jc/conflict-marker-size:
  rerere: honor conflict-marker-size attribute
  rerere: prepare for customizable conflict marker length
  conflict-marker-size: new attribute
  rerere: use ll_merge() instead of using xdl_merge()
  merge-tree: use ll_merge() not xdl_merge()
  xdl_merge(): allow passing down marker_size in xmparam_t
  xdl_merge(): introduce xmparam_t for merge specific parameters
  git_attr(): fix function signature

Conflicts:
builtin-merge-file.c
ll-merge.c
xdiff/xdiff.h
xdiff/xmerge.c

1  2 
archive.c
builtin-merge-file.c
builtin-pack-objects.c
convert.c
ll-merge.c
ll-merge.h
rerere.c
xdiff/xdiff.h
xdiff/xmerge.c

diff --combined archive.c
index 5b88507374f08e118a83fe7479766e078c5616ca,a9ebdc5d54fba9010b9eaa52f5a9eb2b0cef0dc4..d700af3b62f35091f9c628a5a2c0d8449e2fe439
+++ b/archive.c
@@@ -87,8 -87,8 +87,8 @@@ static void setup_archive_check(struct 
        static struct git_attr *attr_export_subst;
  
        if (!attr_export_ignore) {
-               attr_export_ignore = git_attr("export-ignore", 13);
-               attr_export_subst = git_attr("export-subst", 12);
+               attr_export_ignore = git_attr("export-ignore");
+               attr_export_subst = git_attr("export-subst");
        }
        check[0].attr = attr_export_ignore;
        check[1].attr = attr_export_subst;
@@@ -211,33 -211,10 +211,33 @@@ static const struct archiver *lookup_ar
        return NULL;
  }
  
 +static int reject_entry(const unsigned char *sha1, const char *base,
 +                      int baselen, const char *filename, unsigned mode,
 +                      int stage, void *context)
 +{
 +      return -1;
 +}
 +
 +static int path_exists(struct tree *tree, const char *path)
 +{
 +      const char *pathspec[] = { path, NULL };
 +
 +      if (read_tree_recursive(tree, "", 0, 0, pathspec, reject_entry, NULL))
 +              return 1;
 +      return 0;
 +}
 +
  static void parse_pathspec_arg(const char **pathspec,
                struct archiver_args *ar_args)
  {
 -      ar_args->pathspec = get_pathspec("", pathspec);
 +      ar_args->pathspec = pathspec = get_pathspec("", pathspec);
 +      if (pathspec) {
 +              while (*pathspec) {
 +                      if (!path_exists(ar_args->tree, *pathspec))
 +                              die("path not found: %s", *pathspec);
 +                      pathspec++;
 +              }
 +      }
  }
  
  static void parse_treeish_arg(const char **argv,
diff --combined builtin-merge-file.c
index 1efc4e09bc12c73978789502d041fd596397aeb3,11c3524a77812700e96fe830c515d5d85823d037..1e70073a7ed022675031706a8e9f8c57ff3aa2a9
@@@ -25,20 -25,15 +25,20 @@@ int cmd_merge_file(int argc, const cha
        const char *names[3] = { NULL, NULL, NULL };
        mmfile_t mmfs[3];
        mmbuffer_t result = {NULL, 0};
-       xpparam_t xpp = {XDF_NEED_MINIMAL};
+       xmparam_t xmp = {{XDF_NEED_MINIMAL}};
        int ret = 0, i = 0, to_stdout = 0;
 -      int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
 -      int merge_style = 0, quiet = 0;
 +      int level = XDL_MERGE_ZEALOUS_ALNUM;
 +      int style = 0, quiet = 0;
 +      int favor = 0;
        int nongit;
  
        struct option options[] = {
                OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
 -              OPT_SET_INT(0, "diff3", &merge_style, "use a diff3 based merge", XDL_MERGE_DIFF3),
 +              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",
 +                          XDL_MERGE_FAVOR_OURS),
 +              OPT_SET_INT(0, "theirs", &favor, "for conflicts, use their version",
 +                          XDL_MERGE_FAVOR_THEIRS),
                OPT__QUIET(&quiet),
                OPT_CALLBACK('L', NULL, names, "name",
                             "set labels for file1/orig_file/file2", &label_cb),
@@@ -50,7 -45,7 +50,7 @@@
                /* Read the configuration file */
                git_config(git_xmerge_config, NULL);
                if (0 <= git_xmerge_style)
 -                      merge_style = git_xmerge_style;
 +                      style = git_xmerge_style;
        }
  
        argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
@@@ -73,7 -68,7 +73,7 @@@
        }
  
        ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
-                       &xpp, XDL_MERGE_FLAGS(level, style, favor), &result);
 -                      &xmp, merge_level | merge_style, &result);
++                      &xmp, XDL_MERGE_FLAGS(level, style, favor), &result);
  
        for (i = 0; i < 3; i++)
                free(mmfs[i].ptr);
diff --combined builtin-pack-objects.c
index 890f45cf2070a476c0325033e898e9345091fef1,9beff352d5076b6350991d24579b6f9b57d018d5..59b07fe491f37fbe47e04fe834138720336e3627
@@@ -673,7 -673,7 +673,7 @@@ static void setup_delta_attr_check(stru
        static struct git_attr *attr_delta;
  
        if (!attr_delta)
-               attr_delta = git_attr("delta", 5);
+               attr_delta = git_attr("delta");
  
        check[0].attr = attr_delta;
  }
@@@ -1256,15 -1256,15 +1256,15 @@@ static int delta_cacheable(unsigned lon
  
  #ifdef THREADED_DELTA_SEARCH
  
 -static pthread_mutex_t read_mutex = PTHREAD_MUTEX_INITIALIZER;
 +static pthread_mutex_t read_mutex;
  #define read_lock()           pthread_mutex_lock(&read_mutex)
  #define read_unlock()         pthread_mutex_unlock(&read_mutex)
  
 -static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
 +static pthread_mutex_t cache_mutex;
  #define cache_lock()          pthread_mutex_lock(&cache_mutex)
  #define cache_unlock()                pthread_mutex_unlock(&cache_mutex)
  
 -static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
 +static pthread_mutex_t progress_mutex;
  #define progress_lock()               pthread_mutex_lock(&progress_mutex)
  #define progress_unlock()     pthread_mutex_unlock(&progress_mutex)
  
@@@ -1591,26 -1591,7 +1591,26 @@@ struct thread_params 
        unsigned *processed;
  };
  
 -static pthread_cond_t progress_cond = PTHREAD_COND_INITIALIZER;
 +static pthread_cond_t progress_cond;
 +
 +/*
 + * Mutex and conditional variable can't be statically-initialized on Windows.
 + */
 +static void init_threaded_search(void)
 +{
 +      pthread_mutex_init(&read_mutex, NULL);
 +      pthread_mutex_init(&cache_mutex, NULL);
 +      pthread_mutex_init(&progress_mutex, NULL);
 +      pthread_cond_init(&progress_cond, NULL);
 +}
 +
 +static void cleanup_threaded_search(void)
 +{
 +      pthread_cond_destroy(&progress_cond);
 +      pthread_mutex_destroy(&read_mutex);
 +      pthread_mutex_destroy(&cache_mutex);
 +      pthread_mutex_destroy(&progress_mutex);
 +}
  
  static void *threaded_find_deltas(void *arg)
  {
@@@ -1649,13 -1630,10 +1649,13 @@@ static void ll_find_deltas(struct objec
        struct thread_params *p;
        int i, ret, active_threads = 0;
  
 +      init_threaded_search();
 +
        if (!delta_search_threads)      /* --threads=0 means autodetect */
                delta_search_threads = online_cpus();
        if (delta_search_threads <= 1) {
                find_deltas(list, &list_size, window, depth, processed);
 +              cleanup_threaded_search();
                return;
        }
        if (progress > pack_to_stdout)
                        active_threads--;
                }
        }
 +      cleanup_threaded_search();
        free(p);
  }
  
diff --combined convert.c
index 950b1f9840663e7536256babb05f68de01a4689b,852fd6488aa44d25a9219bebc09990477354d168..27acce58bc4bec60a394f03db1f6e60e1e4cfc3e
+++ b/convert.c
@@@ -249,11 -249,10 +249,11 @@@ static int filter_buffer(int fd, void *
        struct child_process child_process;
        struct filter_params *params = (struct filter_params *)data;
        int write_err, status;
 -      const char *argv[] = { "sh", "-c", params->cmd, NULL };
 +      const char *argv[] = { params->cmd, NULL };
  
        memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
 +      child_process.use_shell = 1;
        child_process.in = -1;
        child_process.out = fd;
  
@@@ -378,9 -377,9 +378,9 @@@ static void setup_convert_check(struct 
        static struct git_attr *attr_filter;
  
        if (!attr_crlf) {
-               attr_crlf = git_attr("crlf", 4);
-               attr_ident = git_attr("ident", 5);
-               attr_filter = git_attr("filter", 6);
+               attr_crlf = git_attr("crlf");
+               attr_ident = git_attr("ident");
+               attr_filter = git_attr("filter");
                user_convert_tail = &user_convert;
                git_config(read_convert_config, NULL);
        }
diff --combined ll-merge.c
index 070d66dd402bcb7ba51d69974c21a255aa93558b,0dcaae0dd166205e6d17a523789b4b82e5a01f18..4c7f11ba84c67089dce7d725d87a4dd32a245c7f
@@@ -18,7 -18,8 +18,8 @@@ typedef int (*ll_merge_fn)(const struc
                           mmfile_t *orig,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
-                          int flag);
 -                         int virtual_ancestor,
++                         int flag,
+                          int marker_size);
  
  struct ll_merge_driver {
        const char *name;
@@@ -38,14 -39,14 +39,14 @@@ static int ll_binary_merge(const struc
                           mmfile_t *orig,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
-                          int flag)
 -                         int virtual_ancestor, int marker_size)
++                         int flag, int marker_size)
  {
        /*
         * The tentative merge result is "ours" for the final round,
         * or common ancestor for an internal merge.  Still return
         * "conflicted merge" status.
         */
 -      mmfile_t *stolen = virtual_ancestor ? orig : src1;
 +      mmfile_t *stolen = (flag & 01) ? orig : src1;
  
        result->ptr = stolen->ptr;
        result->size = stolen->size;
@@@ -59,11 -60,10 +60,11 @@@ static int ll_xdl_merge(const struct ll
                        mmfile_t *orig,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
-                       int flag)
 -                      int virtual_ancestor, int marker_size)
++                      int flag, int marker_size)
  {
-       xpparam_t xpp;
+       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) ||
                return ll_binary_merge(drv_unused, result,
                                       path,
                                       orig, src1, name1,
-                                      src2, name2, flag);
+                                      src2, name2,
 -                                     virtual_ancestor, marker_size);
++                                     flag, marker_size);
        }
  
-       memset(&xpp, 0, sizeof(xpp));
+       memset(&xmp, 0, sizeof(xmp));
        if (git_xmerge_style >= 0)
                style = git_xmerge_style;
+       if (marker_size > 0)
+               xmp.marker_size = marker_size;
        return xdl_merge(orig,
                         src1, name1,
                         src2, name2,
-                        &xpp, XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, style, favor),
 -                       &xmp, XDL_MERGE_ZEALOUS | style,
++                       &xmp, XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, style, favor),
                         result);
  }
  
@@@ -92,11 -95,10 +96,10 @@@ static int ll_union_merge(const struct 
                          mmfile_t *orig,
                          mmfile_t *src1, const char *name1,
                          mmfile_t *src2, const char *name2,
-                         int flag)
 -                        int virtual_ancestor, int marker_size)
++                        int flag, int marker_size)
  {
        char *src, *dst;
        long size;
-       const int marker_size = 7;
        int status, saved_style;
  
        /* We have to force the RCS "merge" style */
        git_xmerge_style = 0;
        status = ll_xdl_merge(drv_unused, result, path_unused,
                              orig, src1, NULL, src2, NULL,
-                             flag);
 -                            virtual_ancestor, marker_size);
++                            flag, marker_size);
        git_xmerge_style = saved_style;
        if (status <= 0)
                return status;
@@@ -165,17 -167,18 +168,18 @@@ static int ll_ext_merge(const struct ll
                        mmfile_t *orig,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
-                       int flag)
 -                      int virtual_ancestor, int marker_size)
++                      int flag, int marker_size)
  {
-       char temp[3][50];
+       char temp[4][50];
        struct strbuf cmd = STRBUF_INIT;
        struct strbuf_expand_dict_entry dict[] = {
                { "O", temp[0] },
                { "A", temp[1] },
                { "B", temp[2] },
+               { "L", temp[3] },
                { NULL }
        };
 -      const char *args[] = { "sh", "-c", NULL, NULL };
 +      const char *args[] = { NULL, NULL };
        int status, fd, i;
        struct stat st;
  
        create_temp(orig, temp[0]);
        create_temp(src1, temp[1]);
        create_temp(src2, temp[2]);
+       sprintf(temp[3], "%d", marker_size);
  
        strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
  
 -      args[2] = cmd.buf;
 -      status = run_command_v_opt(args, 0);
 +      args[0] = cmd.buf;
 +      status = run_command_v_opt(args, RUN_USING_SHELL);
        fd = open(temp[1], O_RDONLY);
        if (fd < 0)
                goto bad;
@@@ -279,6 -283,7 +284,7 @@@ static int read_merge_config(const cha
                 *    %O - temporary file name for the merge base.
                 *    %A - temporary file name for our version.
                 *    %B - temporary file name for the other branches' version.
+                *    %L - conflict marker length
                 *
                 * The external merge driver should write the results in the
                 * file named by %A, and signal that it has done with zero exit
@@@ -339,16 -344,13 +345,13 @@@ static const struct ll_merge_driver *fi
        return &ll_merge_drv[LL_TEXT_MERGE];
  }
  
- static const char *git_path_check_merge(const char *path)
+ static int git_path_check_merge(const char *path, struct git_attr_check check[2])
  {
-       static struct git_attr_check attr_merge_check;
-       if (!attr_merge_check.attr)
-               attr_merge_check.attr = git_attr("merge", 5);
-       if (git_checkattr(path, 1, &attr_merge_check))
-               return NULL;
-       return attr_merge_check.value;
+       if (!check[0].attr) {
+               check[0].attr = git_attr("merge");
+               check[1].attr = git_attr("conflict-marker-size");
+       }
+       return git_checkattr(path, 2, check);
  }
  
  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;
+       static struct git_attr_check check[2];
+       const char *ll_driver_name = NULL;
+       int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        const struct ll_merge_driver *driver;
 +      int virtual_ancestor = flag & 01;
  
-       ll_driver_name = git_path_check_merge(path);
+       if (!git_path_check_merge(path, check)) {
+               ll_driver_name = check[0].value;
+               if (check[1].value) {
+                       marker_size = atoi(check[1].value);
+                       if (marker_size <= 0)
+                               marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
+               }
+       }
        driver = find_ll_merge_driver(ll_driver_name);
        if (virtual_ancestor && driver->recursive)
                driver = find_ll_merge_driver(driver->recursive);
-       return driver->fn(driver, result_buf, path,
-                         ancestor,
-                         ours, our_label,
-                         theirs, their_label, flag);
+       return driver->fn(driver, result_buf, path, ancestor,
+                         ours, our_label, theirs, their_label,
 -                        virtual_ancestor, marker_size);
++                        flag, marker_size);
+ }
+ int ll_merge_marker_size(const char *path)
+ {
+       static struct git_attr_check check;
+       int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
+       if (!check.attr)
+               check.attr = git_attr("conflict-marker-size");
+       if (!git_checkattr(path, 1, &check) && check.value) {
+               marker_size = atoi(check.value);
+               if (marker_size <= 0)
+                       marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
+       }
+       return marker_size;
  }
diff --combined ll-merge.h
index aaed46dec9dabcd7adc614ded30086f61cdf7b48,ff5d84a345848ff34e068c6fad617f2df5633745..57889227b1782d3792be2046fbb54bca67b779de
@@@ -10,6 -10,8 +10,8 @@@ 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);
  
+ int ll_merge_marker_size(const char *path);
  #endif
diff --combined rerere.c
index 70d0f7afffe983e6c70ad8494b095c1292393745,b988b467fa06d109d8164bccf213a362e87fb1d4..a86d73d9dcb0d07283885825a16286b3c7990ea2
+++ b/rerere.c
@@@ -1,11 -1,11 +1,11 @@@
  #include "cache.h"
  #include "string-list.h"
  #include "rerere.h"
- #include "xdiff/xdiff.h"
  #include "xdiff-interface.h"
  #include "dir.h"
  #include "resolve-undo.h"
  #include "ll-merge.h"
+ #include "attr.h"
  
  /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
  static int rerere_enabled = -1;
@@@ -99,6 -99,28 +99,28 @@@ static void rerere_io_putstr(const cha
                ferr_puts(str, io->output, &io->wrerror);
  }
  
+ static void rerere_io_putconflict(int ch, int size, struct rerere_io *io)
+ {
+       char buf[64];
+       while (size) {
+               if (size < sizeof(buf) - 2) {
+                       memset(buf, ch, size);
+                       buf[size] = '\n';
+                       buf[size + 1] = '\0';
+                       size = 0;
+               } else {
+                       int sz = sizeof(buf) - 1;
+                       if (size <= sz)
+                               sz -= (sz - size) + 1;
+                       memset(buf, ch, sz);
+                       buf[sz] = '\0';
+                       size -= sz;
+               }
+               rerere_io_putstr(buf, io);
+       }
+ }
  static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io)
  {
        if (io->output)
@@@ -116,7 -138,17 +138,17 @@@ static int rerere_file_getline(struct s
        return strbuf_getwholeline(sb, io->input, '\n');
  }
  
- static int handle_path(unsigned char *sha1, struct rerere_io *io)
+ static int is_cmarker(char *buf, int marker_char, int marker_size, int want_sp)
+ {
+       while (marker_size--)
+               if (*buf++ != marker_char)
+                       return 0;
+       if (want_sp && *buf != ' ')
+               return 0;
+       return isspace(*buf);
+ }
+ static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
  {
        git_SHA_CTX ctx;
        int hunk_no = 0;
                git_SHA1_Init(&ctx);
  
        while (!io->getline(&buf, io)) {
-               if (!prefixcmp(buf.buf, "<<<<<<< ")) {
+               if (is_cmarker(buf.buf, '<', marker_size, 1)) {
                        if (hunk != RR_CONTEXT)
                                goto bad;
                        hunk = RR_SIDE_1;
-               } else if (!prefixcmp(buf.buf, "|||||||") && isspace(buf.buf[7])) {
+               } else if (is_cmarker(buf.buf, '|', marker_size, 0)) {
                        if (hunk != RR_SIDE_1)
                                goto bad;
                        hunk = RR_ORIGINAL;
-               } else if (!prefixcmp(buf.buf, "=======") && isspace(buf.buf[7])) {
+               } else if (is_cmarker(buf.buf, '=', marker_size, 0)) {
                        if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)
                                goto bad;
                        hunk = RR_SIDE_2;
-               } else if (!prefixcmp(buf.buf, ">>>>>>> ")) {
+               } else if (is_cmarker(buf.buf, '>', marker_size, 1)) {
                        if (hunk != RR_SIDE_2)
                                goto bad;
                        if (strbuf_cmp(&one, &two) > 0)
                                strbuf_swap(&one, &two);
                        hunk_no++;
                        hunk = RR_CONTEXT;
-                       rerere_io_putstr("<<<<<<<\n", io);
+                       rerere_io_putconflict('<', marker_size, io);
                        rerere_io_putmem(one.buf, one.len, io);
-                       rerere_io_putstr("=======\n", io);
+                       rerere_io_putconflict('=', marker_size, io);
                        rerere_io_putmem(two.buf, two.len, io);
-                       rerere_io_putstr(">>>>>>>\n", io);
+                       rerere_io_putconflict('>', marker_size, io);
                        if (sha1) {
                                git_SHA1_Update(&ctx, one.buf ? one.buf : "",
                                            one.len + 1);
@@@ -190,6 -222,7 +222,7 @@@ static int handle_file(const char *path
  {
        int hunk_no = 0;
        struct rerere_io_file io;
+       int marker_size = ll_merge_marker_size(path);
  
        memset(&io, 0, sizeof(io));
        io.io.getline = rerere_file_getline;
                }
        }
  
-       hunk_no = handle_path(sha1, (struct rerere_io *)&io);
+       hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);
  
        fclose(io.input);
        if (io.io.wrerror)
@@@ -256,6 -289,7 +289,7 @@@ static int handle_cache(const char *pat
        struct cache_entry *ce;
        int pos, len, i, hunk_no;
        struct rerere_io_mem io;
+       int marker_size = ll_merge_marker_size(path);
  
        /*
         * Reproduce the conflicted merge in-core
        strbuf_init(&io.input, 0);
        strbuf_attach(&io.input, result.ptr, result.size, result.size);
  
-       hunk_no = handle_path(sha1, (struct rerere_io *)&io);
+       hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);
        strbuf_release(&io.input);
        if (io.io.output)
                fclose(io.io.output);
@@@ -332,7 -366,6 +366,6 @@@ static int merge(const char *name, cons
        int ret;
        mmfile_t cur, base, other;
        mmbuffer_t result = {NULL, 0};
-       xpparam_t xpp = {XDF_NEED_MINIMAL};
  
        if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0)
                return 1;
                        read_mmfile(&base, rerere_path(name, "preimage")) ||
                        read_mmfile(&other, rerere_path(name, "postimage")))
                return 1;
-       ret = xdl_merge(&base, &cur, "", &other, "",
-                       &xpp, XDL_MERGE_ZEALOUS, &result);
+       ret = ll_merge(&result, path, &base, &cur, "", &other, "", 0);
        if (!ret) {
                FILE *f = fopen(path, "w");
                if (!f)
@@@ -493,7 -525,7 +525,7 @@@ static int is_rerere_enabled(void
        return 1;
  }
  
 -int setup_rerere(struct string_list *merge_rr)
 +int setup_rerere(struct string_list *merge_rr, int flags)
  {
        int fd;
  
        if (!is_rerere_enabled())
                return -1;
  
 +      if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
 +              rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
        merge_rr_path = git_pathdup("MERGE_RR");
        fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
                                       LOCK_DIE_ON_ERROR);
        return fd;
  }
  
 -int rerere(void)
 +int rerere(int flags)
  {
        struct string_list merge_rr = { NULL, 0, 0, 1 };
        int fd;
  
 -      fd = setup_rerere(&merge_rr);
 +      fd = setup_rerere(&merge_rr, flags);
        if (fd < 0)
                return 0;
        return do_plain_rerere(&merge_rr, fd);
@@@ -556,7 -586,7 +588,7 @@@ int rerere_forget(const char **pathspec
        if (read_cache() < 0)
                return error("Could not read index");
  
 -      fd = setup_rerere(&merge_rr);
 +      fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
  
        unmerge_cache(pathspec);
        find_conflict(&conflict);
diff --combined xdiff/xdiff.h
index 8a0efed3139fdf2f9dccbc0163e2943d66460a4d,22f39134274bcb6c10eba826a0d35a41acec2de1..3f6229edbeb21bb1ca0c423d88390f3b5a05b5a2
@@@ -58,12 -58,6 +58,12 @@@ extern "C" 
  #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))
 +
  /* merge output styles */
  #define XDL_MERGE_DIFF3 0x8000
  #define XDL_MERGE_STYLE_MASK 0x8000
@@@ -114,9 -108,16 +114,16 @@@ 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);
  
+ typedef struct s_xmparam {
+       xpparam_t xpp;
+       int marker_size;
+ } 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,
-               xpparam_t const *xpp, int flags, mmbuffer_t *result);
 -              xmparam_t const *xmp, int level, mmbuffer_t *result);
++              xmparam_t const *xmp, int flags, mmbuffer_t *result);
  
  #ifdef __cplusplus
  }
diff --combined xdiff/xmerge.c
index b2ddc75376f530a07cb951bc8314c4a635517af5,68c815f9d3f81746a3545ef715291141a1c648ad..8cbe45e6755487dbe3759398375a11d05f6d91bc
@@@ -145,13 -145,15 +145,15 @@@ static int xdl_orig_copy(xdfenv_t *xe, 
  static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                              xdfenv_t *xe2, const char *name2,
                              int size, int i, int style,
-                             xdmerge_t *m, char *dest)
+                             xdmerge_t *m, char *dest, int marker_size)
  {
-       const int marker_size = 7;
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
        int j;
  
+       if (marker_size <= 0)
+               marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        /* Before conflicting part */
        size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
                              dest ? dest + size : NULL);
  
  static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                 xdfenv_t *xe2, const char *name2,
-                                xdmerge_t *m, char *dest, int style)
 +                               int favor,
+                                xdmerge_t *m, char *dest, int style,
+                                int marker_size)
  {
        int size, i;
  
        for (size = i = 0; m; m = m->next) {
 +              if (favor && !m->mode)
 +                      m->mode = favor;
 +
                if (m->mode == 0)
                        size = fill_conflict_hunk(xe1, name1, xe2, name2,
-                                                 size, i, style, m, dest);
+                                                 size, i, style, m, dest,
+                                                 marker_size);
                else if (m->mode == 1)
                        size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
                                              dest ? dest + size : NULL);
@@@ -390,12 -390,12 +394,13 @@@ static int xdl_simplify_non_conflicts(x
   */
  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, xpparam_t const *xpp, mmbuffer_t *result) {
+               int flags, 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);
  
        if (style == XDL_MERGE_DIFF3) {
                /*
        }
        /* output */
        if (result) {
+               int marker_size = xmp->marker_size;
                int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
-                       favor, changes, NULL, style);
 -                                               changes, NULL, style,
++                                               favor, changes, NULL, style,
+                                                marker_size);
                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,
 +              xdl_fill_merge_buffer(xe1, name1, xe2, name2, favor, changes,
-                                     result->ptr, style);
+                                     result->ptr, style, marker_size);
        }
        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 flags, mmbuffer_t *result) {
+               xmparam_t const *xmp, int flags, mmbuffer_t *result) {
        xdchange_t *xscr1, *xscr2;
        xdfenv_t xe1, xe2;
        int status;
+       xpparam_t const *xpp = &xmp->xpp;
  
        result->ptr = NULL;
        result->size = 0;
        } else {
                status = xdl_do_merge(&xe1, xscr1, name1,
                                      &xe2, xscr2, name2,
-                                     flags, xpp, result);
+                                     flags, xmp, result);
        }
        xdl_free_script(xscr1);
        xdl_free_script(xscr2);