{"thread":{"id":"22256","subject":"[PATCH 0/8] Rescuing repeated merge of Documentation/git-merge.txt","startedAt":"2010-01-17T09:38:56Z","lastAt":"2010-01-17T20:40:13Z","messageCount":13,"participants":["Junio C Hamano","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"131928","messageId":"1263721144-18605-1-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":null,"subject":"[PATCH 0/8] Rescuing repeated merge of Documentation/git-merge.txt","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:38:56Z","receivedAt":"2010-01-17T09:38:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ever since I started queuing Thomas's documentation updates in 'pu',\nrebuilding the branch involved manual re-integration for conflicts in\nDocumentation/git-merge.txt.  This is because the tracked contents in\nthe file has lines that exactly match the conflict marker patterns (of\ncourse, they are examples of how conflicts are shown).\n\nI am not blaming Thomas; the blame lies squarely on the inability of\n'rerere' to deal with such a situation.  It often is enough to do:\n\n\tgit diff pu@{4.hours} Documentation/git-merge.txt\n\nto check that nothing else has changed since the last merge, and then\n\n\tgit co pu@{4.hours} Documentation/git-merge.txt\n\nto resurrect the previous result, but it still is irritating.\n\nThis series is to help me cope with this particular merge by allowing the\nattribute mechanism.  By having this entry in my .git/info/attributes:\n\n\tDocumentation/git-merge.txt\tconflict-marker-size=32\n\n\"git merge\" leaves conflict markers that are 32 chars long (instead of the\nusual 7), \"git rerere\" that is run internally when \"git merge\" results in\nconflicts sees only the real conflict markers as such without getting\nconfused by the example in the contents, and \"git rerere\" called to record\nthe resolution does the right thing.\n\nJunio C Hamano (8):\n  git_attr(): fix function signature\n  xdl_merge(): introduce xmparam_t for merge specific parameters\n  xdl_merge(): allow passing down marker_size in xmparam_t\n  merge-tree: use ll_merge() not xdl_merge()\n  rerere: use ll_merge() instead of using xdl_merge()\n  conflict-marker-size: new attribute\n  rerere: prepare for customizable conflict marker length\n  rerere: honor conflict-marker-size attribute\n\n archive.c              |    4 +-\n attr.c                 |   11 +++++--\n attr.h                 |    2 +-\n builtin-check-attr.c   |    2 +-\n builtin-merge-file.c   |    4 +-\n builtin-pack-objects.c |    2 +-\n convert.c              |    6 ++--\n ll-merge.c             |   80 +++++++++++++++++++++++++++++++-----------------\n ll-merge.h             |    2 +\n merge-file.c           |   16 ++++-----\n merge-tree.c           |    4 +-\n rerere.c               |   57 +++++++++++++++++++++++++--------\n userdiff.c             |    2 +-\n ws.c                   |    2 +-\n xdiff/xdiff.h          |    9 +++++-\n xdiff/xmerge.c         |   26 ++++++++++-----\n 16 files changed, 151 insertions(+), 78 deletions(-)\n"},{"id":"131929","messageId":"1263721144-18605-2-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 1/8] git_attr(): fix function signature","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:38:57Z","receivedAt":"2010-01-17T09:38:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The function took (name, namelen) as its arguments, but all the public\ncallers wanted to pass a full string.\n\nDemote the counted-string interface to an internal API status, and allow\npublic callers to just pass the string to the function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n archive.c              |    4 ++--\n attr.c                 |   11 ++++++++---\n attr.h                 |    2 +-\n builtin-check-attr.c   |    2 +-\n builtin-pack-objects.c |    2 +-\n convert.c              |    6 +++---\n ll-merge.c             |    2 +-\n userdiff.c             |    2 +-\n ws.c                   |    2 +-\n 9 files changed, 19 insertions(+), 14 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 55b2732..a9ebdc5 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -87,8 +87,8 @@ static void setup_archive_check(struct git_attr_check *check)\n \tstatic struct git_attr *attr_export_subst;\n \n \tif (!attr_export_ignore) {\n-\t\tattr_export_ignore = git_attr(\"export-ignore\", 13);\n-\t\tattr_export_subst = git_attr(\"export-subst\", 12);\n+\t\tattr_export_ignore = git_attr(\"export-ignore\");\n+\t\tattr_export_subst = git_attr(\"export-subst\");\n \t}\n \tcheck[0].attr = attr_export_ignore;\n \tcheck[1].attr = attr_export_subst;\ndiff --git a/attr.c b/attr.c\nindex 55bdb7c..f5346ed 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -65,7 +65,7 @@ static int invalid_attr_name(const char *name, int namelen)\n \treturn 0;\n }\n \n-struct git_attr *git_attr(const char *name, int len)\n+static struct git_attr *git_attr_internal(const char *name, int len)\n {\n \tunsigned hval = hash_name(name, len);\n \tunsigned pos = hval % HASHSIZE;\n@@ -95,6 +95,11 @@ struct git_attr *git_attr(const char *name, int len)\n \treturn a;\n }\n \n+struct git_attr *git_attr(const char *name)\n+{\n+\treturn git_attr_internal(name, strlen(name));\n+}\n+\n /*\n  * .gitattributes file is one line per record, each of which is\n  *\n@@ -162,7 +167,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,\n \t\telse {\n \t\t\te->setto = xmemdupz(equals + 1, ep - equals - 1);\n \t\t}\n-\t\te->attr = git_attr(cp, len);\n+\t\te->attr = git_attr_internal(cp, len);\n \t}\n \t(*num_attr)++;\n \treturn ep + strspn(ep, blank);\n@@ -221,7 +226,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,\n \t\t\t      sizeof(struct attr_state) * num_attr +\n \t\t\t      (is_macro ? 0 : namelen + 1));\n \t\tif (is_macro)\n-\t\t\tres->u.attr = git_attr(name, namelen);\n+\t\t\tres->u.attr = git_attr_internal(name, namelen);\n \t\telse {\n \t\t\tres->u.pattern = (char *)&(res->state[num_attr]);\n \t\t\tmemcpy(res->u.pattern, name, namelen);\ndiff --git a/attr.h b/attr.h\nindex 69b5767..450f49d 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -8,7 +8,7 @@ struct git_attr;\n  * Given a string, return the gitattribute object that\n  * corresponds to it.\n  */\n-struct git_attr *git_attr(const char *, int);\n+struct git_attr *git_attr(const char *);\n \n /* Internal use */\n extern const char git_attr__true[];\ndiff --git a/builtin-check-attr.c b/builtin-check-attr.c\nindex 8bd0430..3016d29 100644\n--- a/builtin-check-attr.c\n+++ b/builtin-check-attr.c\n@@ -106,7 +106,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)\n \t\tconst char *name;\n \t\tstruct git_attr *a;\n \t\tname = argv[i];\n-\t\ta = git_attr(name, strlen(name));\n+\t\ta = git_attr(name);\n \t\tif (!a)\n \t\t\treturn error(\"%s: not a valid attribute name\", name);\n \t\tcheck[i].attr = a;\ndiff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\nindex 4429d53..9beff35 100644\n--- a/builtin-pack-objects.c\n+++ b/builtin-pack-objects.c\n@@ -673,7 +673,7 @@ static void setup_delta_attr_check(struct git_attr_check *check)\n \tstatic struct git_attr *attr_delta;\n \n \tif (!attr_delta)\n-\t\tattr_delta = git_attr(\"delta\", 5);\n+\t\tattr_delta = git_attr(\"delta\");\n \n \tcheck[0].attr = attr_delta;\n }\ndiff --git a/convert.c b/convert.c\nindex 491e714..852fd64 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -377,9 +377,9 @@ static void setup_convert_check(struct git_attr_check *check)\n \tstatic struct git_attr *attr_filter;\n \n \tif (!attr_crlf) {\n-\t\tattr_crlf = git_attr(\"crlf\", 4);\n-\t\tattr_ident = git_attr(\"ident\", 5);\n-\t\tattr_filter = git_attr(\"filter\", 6);\n+\t\tattr_crlf = git_attr(\"crlf\");\n+\t\tattr_ident = git_attr(\"ident\");\n+\t\tattr_filter = git_attr(\"filter\");\n \t\tuser_convert_tail = &user_convert;\n \t\tgit_config(read_convert_config, NULL);\n \t}\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 2d6b6d6..f4b0a07 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -344,7 +344,7 @@ static const char *git_path_check_merge(const char *path)\n \tstatic struct git_attr_check attr_merge_check;\n \n \tif (!attr_merge_check.attr)\n-\t\tattr_merge_check.attr = git_attr(\"merge\", 5);\n+\t\tattr_merge_check.attr = git_attr(\"merge\");\n \n \tif (git_checkattr(path, 1, &attr_merge_check))\n \t\treturn NULL;\ndiff --git a/userdiff.c b/userdiff.c\nindex 57529ae..df99249 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -198,7 +198,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path)\n \tstruct git_attr_check check;\n \n \tif (!attr)\n-\t\tattr = git_attr(\"diff\", 4);\n+\t\tattr = git_attr(\"diff\");\n \tcheck.attr = attr;\n \n \tif (!path)\ndiff --git a/ws.c b/ws.c\nindex 760b574..c089338 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -64,7 +64,7 @@ static void setup_whitespace_attr_check(struct git_attr_check *check)\n \tstatic struct git_attr *attr_whitespace;\n \n \tif (!attr_whitespace)\n-\t\tattr_whitespace = git_attr(\"whitespace\", 10);\n+\t\tattr_whitespace = git_attr(\"whitespace\");\n \tcheck[0].attr = attr_whitespace;\n }\n \n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131930","messageId":"1263721144-18605-3-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 2/8] xdl_merge(): introduce xmparam_t for merge specific parameters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:38:58Z","receivedAt":"2010-01-17T09:38:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"So far we have only needed to be able to pass an option that is generic to\nxdiff family of functions to this function.  Extend the interface so that\nwe can give it merge specific parameters.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-merge-file.c |    4 ++--\n ll-merge.c           |    6 +++---\n merge-file.c         |    6 +++---\n rerere.c             |    4 ++--\n xdiff/xdiff.h        |    6 +++++-\n xdiff/xmerge.c       |    3 ++-\n 6 files changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin-merge-file.c b/builtin-merge-file.c\nindex afd2ea7..11c3524 100644\n--- a/builtin-merge-file.c\n+++ b/builtin-merge-file.c\n@@ -25,7 +25,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \tconst char *names[3] = { NULL, NULL, NULL };\n \tmmfile_t mmfs[3];\n \tmmbuffer_t result = {NULL, 0};\n-\txpparam_t xpp = {XDF_NEED_MINIMAL};\n+\txmparam_t xmp = {{XDF_NEED_MINIMAL}};\n \tint ret = 0, i = 0, to_stdout = 0;\n \tint merge_level = XDL_MERGE_ZEALOUS_ALNUM;\n \tint merge_style = 0, quiet = 0;\n@@ -68,7 +68,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t}\n \n \tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xpp, merge_level | merge_style, &result);\n+\t\t\t&xmp, merge_level | merge_style, &result);\n \n \tfor (i = 0; i < 3; i++)\n \t\tfree(mmfs[i].ptr);\ndiff --git a/ll-merge.c b/ll-merge.c\nindex f4b0a07..be2bf43 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -61,7 +61,7 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\tmmfile_t *src2, const char *name2,\n \t\t\tint virtual_ancestor)\n {\n-\txpparam_t xpp;\n+\txmparam_t xmp;\n \tint style = 0;\n \n \tif (buffer_is_binary(orig->ptr, orig->size) ||\n@@ -76,13 +76,13 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t\t       virtual_ancestor);\n \t}\n \n-\tmemset(&xpp, 0, sizeof(xpp));\n+\tmemset(&xmp, 0, sizeof(xmp));\n \tif (git_xmerge_style >= 0)\n \t\tstyle = git_xmerge_style;\n \treturn xdl_merge(orig,\n \t\t\t src1, name1,\n \t\t\t src2, name2,\n-\t\t\t &xpp, XDL_MERGE_ZEALOUS | style,\n+\t\t\t &xmp, XDL_MERGE_ZEALOUS | style,\n \t\t\t result);\n }\n \ndiff --git a/merge-file.c b/merge-file.c\nindex 3120a95..5c00c7e 100644\n--- a/merge-file.c\n+++ b/merge-file.c\n@@ -27,12 +27,12 @@ static void free_mmfile(mmfile_t *f)\n static void *three_way_filemerge(mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)\n {\n \tmmbuffer_t res;\n-\txpparam_t xpp;\n+\txmparam_t xmp;\n \tint merge_status;\n \n-\tmemset(&xpp, 0, sizeof(xpp));\n+\tmemset(&xmp, 0, sizeof(xmp));\n \tmerge_status = xdl_merge(base, our, \".our\", their, \".their\",\n-\t\t&xpp, XDL_MERGE_ZEALOUS, &res);\n+\t\t&xmp, XDL_MERGE_ZEALOUS, &res);\n \n \tif (merge_status < 0)\n \t\treturn NULL;\ndiff --git a/rerere.c b/rerere.c\nindex d92990a..adb0694 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -332,7 +332,7 @@ static int merge(const char *name, const char *path)\n \tint ret;\n \tmmfile_t cur, base, other;\n \tmmbuffer_t result = {NULL, 0};\n-\txpparam_t xpp = {XDF_NEED_MINIMAL};\n+\txmparam_t xmp = {{XDF_NEED_MINIMAL}};\n \n \tif (handle_file(path, NULL, rerere_path(name, \"thisimage\")) < 0)\n \t\treturn 1;\n@@ -342,7 +342,7 @@ static int merge(const char *name, const char *path)\n \t\t\tread_mmfile(&other, rerere_path(name, \"postimage\")))\n \t\treturn 1;\n \tret = xdl_merge(&base, &cur, \"\", &other, \"\",\n-\t\t\t&xpp, XDL_MERGE_ZEALOUS, &result);\n+\t\t\t&xmp, XDL_MERGE_ZEALOUS, &result);\n \tif (!ret) {\n \t\tFILE *f = fopen(path, \"w\");\n \t\tif (!f)\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 4da052a..b265909 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -108,9 +108,13 @@ long xdl_mmfile_size(mmfile_t *mmf);\n int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \t     xdemitconf_t const *xecfg, xdemitcb_t *ecb);\n \n+typedef struct s_xmparam {\n+\txpparam_t xpp;\n+} xmparam_t;\n+\n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int level, mmbuffer_t *result);\n+\t\txmparam_t const *xmp, int level, mmbuffer_t *result);\n \n #ifdef __cplusplus\n }\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 1cb65a9..5c37b4e 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -538,10 +538,11 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n-\t\txpparam_t const *xpp, int flags, mmbuffer_t *result) {\n+\t\txmparam_t const *xmp, int flags, mmbuffer_t *result) {\n \txdchange_t *xscr1, *xscr2;\n \txdfenv_t xe1, xe2;\n \tint status;\n+\txpparam_t const *xpp = &xmp->xpp;\n \n \tresult->ptr = NULL;\n \tresult->size = 0;\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131933","messageId":"1263721144-18605-4-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 3/8] xdl_merge(): allow passing down marker_size in xmparam_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:38:59Z","receivedAt":"2010-01-17T09:38:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This allows the callers of xdl_merge() to pass marker_size (defaults to 7)\nin xmparam_t argument, to use conflict markers of non-default length.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n xdiff/xdiff.h  |    3 +++\n xdiff/xmerge.c |   23 +++++++++++++++--------\n 2 files changed, 18 insertions(+), 8 deletions(-)\n\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex b265909..22f3913 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -110,8 +110,11 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \n typedef struct s_xmparam {\n \txpparam_t xpp;\n+\tint marker_size;\n } xmparam_t;\n \n+#define DEFAULT_CONFLICT_MARKER_SIZE 7\n+\n int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmmfile_t *mf2, const char *name2,\n \t\txmparam_t const *xmp, int level, mmbuffer_t *result);\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 5c37b4e..68c815f 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -145,13 +145,15 @@ static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)\n static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,\n \t\t\t      xdfenv_t *xe2, const char *name2,\n \t\t\t      int size, int i, int style,\n-\t\t\t      xdmerge_t *m, char *dest)\n+\t\t\t      xdmerge_t *m, char *dest, int marker_size)\n {\n-\tconst int marker_size = 7;\n \tint marker1_size = (name1 ? strlen(name1) + 1 : 0);\n \tint marker2_size = (name2 ? strlen(name2) + 1 : 0);\n \tint j;\n \n+\tif (marker_size <= 0)\n+\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n+\n \t/* Before conflicting part */\n \tsize += xdl_recs_copy(xe1, i, m->i1 - i, 0,\n \t\t\t      dest ? dest + size : NULL);\n@@ -214,14 +216,16 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,\n \n static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n \t\t\t\t xdfenv_t *xe2, const char *name2,\n-\t\t\t\t xdmerge_t *m, char *dest, int style)\n+\t\t\t\t xdmerge_t *m, char *dest, int style,\n+\t\t\t\t int marker_size)\n {\n \tint size, i;\n \n \tfor (size = i = 0; m; m = m->next) {\n \t\tif (m->mode == 0)\n \t\t\tsize = fill_conflict_hunk(xe1, name1, xe2, name2,\n-\t\t\t\t\t\t  size, i, style, m, dest);\n+\t\t\t\t\t\t  size, i, style, m, dest,\n+\t\t\t\t\t\t  marker_size);\n \t\telse if (m->mode == 1)\n \t\t\tsize += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,\n \t\t\t\t\t      dest ? dest + size : NULL);\n@@ -386,8 +390,9 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,\n  */\n static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t\txdfenv_t *xe2, xdchange_t *xscr2, const char *name2,\n-\t\tint flags, xpparam_t const *xpp, mmbuffer_t *result) {\n+\t\tint flags, xmparam_t const *xmp, mmbuffer_t *result) {\n \txdmerge_t *changes, *c;\n+\txpparam_t const *xpp = &xmp->xpp;\n \tint i0, i1, i2, chg0, chg1, chg2;\n \tint level = flags & XDL_MERGE_LEVEL_MASK;\n \tint style = flags & XDL_MERGE_STYLE_MASK;\n@@ -522,8 +527,10 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t}\n \t/* output */\n \tif (result) {\n+\t\tint marker_size = xmp->marker_size;\n \t\tint size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,\n-\t\t\tchanges, NULL, style);\n+\t\t\t\t\t\t changes, NULL, style,\n+\t\t\t\t\t\t marker_size);\n \t\tresult->ptr = xdl_malloc(size);\n \t\tif (!result->ptr) {\n \t\t\txdl_cleanup_merge(changes);\n@@ -531,7 +538,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t\t}\n \t\tresult->size = size;\n \t\txdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,\n-\t\t\t\t      result->ptr, style);\n+\t\t\t\t      result->ptr, style, marker_size);\n \t}\n \treturn xdl_cleanup_merge(changes);\n }\n@@ -575,7 +582,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t} else {\n \t\tstatus = xdl_do_merge(&xe1, xscr1, name1,\n \t\t\t\t      &xe2, xscr2, name2,\n-\t\t\t\t      flags, xpp, result);\n+\t\t\t\t      flags, xmp, result);\n \t}\n \txdl_free_script(xscr1);\n \txdl_free_script(xscr2);\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131934","messageId":"1263721144-18605-5-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 4/8] merge-tree: use ll_merge() not xdl_merge()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:39:00Z","receivedAt":"2010-01-17T09:39:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ll_merge() interface was designed to merge contents under git control\nwhile taking per-path attributes into account.  Update the three-way\nmerge implementation used by merge-tree to use it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n merge-file.c |   16 +++++++---------\n merge-tree.c |    4 ++--\n 2 files changed, 9 insertions(+), 11 deletions(-)\n\ndiff --git a/merge-file.c b/merge-file.c\nindex 5c00c7e..fd34d76 100644\n--- a/merge-file.c\n+++ b/merge-file.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n #include \"xdiff-interface.h\"\n+#include \"ll-merge.h\"\n #include \"blob.h\"\n \n static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)\n@@ -24,16 +25,13 @@ static void free_mmfile(mmfile_t *f)\n \tfree(f->ptr);\n }\n \n-static void *three_way_filemerge(mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)\n+static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)\n {\n-\tmmbuffer_t res;\n-\txmparam_t xmp;\n \tint merge_status;\n+\tmmbuffer_t res;\n \n-\tmemset(&xmp, 0, sizeof(xmp));\n-\tmerge_status = xdl_merge(base, our, \".our\", their, \".their\",\n-\t\t&xmp, XDL_MERGE_ZEALOUS, &res);\n-\n+\tmerge_status = ll_merge(&res, path, base,\n+\t\t\t\tour, \".our\", their, \".their\", 0);\n \tif (merge_status < 0)\n \t\treturn NULL;\n \n@@ -75,7 +73,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)\n \treturn xdi_diff(f1, f2, &xpp, &xecfg, &ecb);\n }\n \n-void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsigned long *size)\n+void *merge_file(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)\n {\n \tvoid *res = NULL;\n \tmmfile_t f1, f2, common;\n@@ -108,7 +106,7 @@ void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsign\n \t\tif (generate_common_file(&common, &f1, &f2) < 0)\n \t\t\tgoto out_free_f2_f1;\n \t}\n-\tres = three_way_filemerge(&common, &f1, &f2, size);\n+\tres = three_way_filemerge(path, &common, &f1, &f2, size);\n \tfree_mmfile(&common);\n out_free_f2_f1:\n \tfree_mmfile(&f2);\ndiff --git a/merge-tree.c b/merge-tree.c\nindex f01e7c8..37b94d9 100644\n--- a/merge-tree.c\n+++ b/merge-tree.c\n@@ -54,7 +54,7 @@ static const char *explanation(struct merge_list *entry)\n \treturn \"removed in remote\";\n }\n \n-extern void *merge_file(struct blob *, struct blob *, struct blob *, unsigned long *);\n+extern void *merge_file(const char *, struct blob *, struct blob *, struct blob *, unsigned long *);\n \n static void *result(struct merge_list *entry, unsigned long *size)\n {\n@@ -76,7 +76,7 @@ static void *result(struct merge_list *entry, unsigned long *size)\n \ttheir = NULL;\n \tif (entry)\n \t\ttheir = entry->blob;\n-\treturn merge_file(base, our, their, size);\n+\treturn merge_file(entry->path, base, our, their, size);\n }\n \n static void *origin(struct merge_list *entry, unsigned long *size)\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131935","messageId":"1263721144-18605-6-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 5/8] rerere: use ll_merge() instead of using xdl_merge()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:39:01Z","receivedAt":"2010-01-17T09:39:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This allows us to pay attention to the attribute settings and custom\nmerge driver the user sets up.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n rerere.c |    5 +----\n 1 files changed, 1 insertions(+), 4 deletions(-)\n\ndiff --git a/rerere.c b/rerere.c\nindex adb0694..5b8ebcb 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -1,7 +1,6 @@\n #include \"cache.h\"\n #include \"string-list.h\"\n #include \"rerere.h\"\n-#include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n #include \"dir.h\"\n #include \"resolve-undo.h\"\n@@ -332,7 +331,6 @@ static int merge(const char *name, const char *path)\n \tint ret;\n \tmmfile_t cur, base, other;\n \tmmbuffer_t result = {NULL, 0};\n-\txmparam_t xmp = {{XDF_NEED_MINIMAL}};\n \n \tif (handle_file(path, NULL, rerere_path(name, \"thisimage\")) < 0)\n \t\treturn 1;\n@@ -341,8 +339,7 @@ static int merge(const char *name, const char *path)\n \t\t\tread_mmfile(&base, rerere_path(name, \"preimage\")) ||\n \t\t\tread_mmfile(&other, rerere_path(name, \"postimage\")))\n \t\treturn 1;\n-\tret = xdl_merge(&base, &cur, \"\", &other, \"\",\n-\t\t\t&xmp, XDL_MERGE_ZEALOUS, &result);\n+\tret = ll_merge(&result, path, &base, &cur, \"\", &other, \"\", 0);\n \tif (!ret) {\n \t\tFILE *f = fopen(path, \"w\");\n \t\tif (!f)\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131936","messageId":"1263721144-18605-7-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 6/8] conflict-marker-size: new attribute","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:39:02Z","receivedAt":"2010-01-17T09:39:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This can be specified to set the length of the conflict marker (usually 7)\nto a non-default value per path.  Only the callers of ll_merge() that are\naware of the per-path attributes are modified.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n ll-merge.c |   59 ++++++++++++++++++++++++++++++++++-------------------------\n 1 files changed, 34 insertions(+), 25 deletions(-)\n\ndiff --git a/ll-merge.c b/ll-merge.c\nindex be2bf43..d682071 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -18,7 +18,8 @@ typedef int (*ll_merge_fn)(const struct ll_merge_driver *,\n \t\t\t   mmfile_t *orig,\n \t\t\t   mmfile_t *src1, const char *name1,\n \t\t\t   mmfile_t *src2, const char *name2,\n-\t\t\t   int virtual_ancestor);\n+\t\t\t   int virtual_ancestor,\n+\t\t\t   int marker_size);\n \n struct ll_merge_driver {\n \tconst char *name;\n@@ -38,7 +39,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t   mmfile_t *orig,\n \t\t\t   mmfile_t *src1, const char *name1,\n \t\t\t   mmfile_t *src2, const char *name2,\n-\t\t\t   int virtual_ancestor)\n+\t\t\t   int virtual_ancestor, int marker_size)\n {\n \t/*\n \t * The tentative merge result is \"ours\" for the final round,\n@@ -59,7 +60,7 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\tmmfile_t *orig,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n-\t\t\tint virtual_ancestor)\n+\t\t\tint virtual_ancestor, int marker_size)\n {\n \txmparam_t xmp;\n \tint style = 0;\n@@ -73,12 +74,14 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t\t       path,\n \t\t\t\t       orig, src1, name1,\n \t\t\t\t       src2, name2,\n-\t\t\t\t       virtual_ancestor);\n+\t\t\t\t       virtual_ancestor, marker_size);\n \t}\n \n \tmemset(&xmp, 0, sizeof(xmp));\n \tif (git_xmerge_style >= 0)\n \t\tstyle = git_xmerge_style;\n+\tif (marker_size > 0)\n+\t\txmp.marker_size = marker_size;\n \treturn xdl_merge(orig,\n \t\t\t src1, name1,\n \t\t\t src2, name2,\n@@ -92,11 +95,10 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t  mmfile_t *orig,\n \t\t\t  mmfile_t *src1, const char *name1,\n \t\t\t  mmfile_t *src2, const char *name2,\n-\t\t\t  int virtual_ancestor)\n+\t\t\t  int virtual_ancestor, int marker_size)\n {\n \tchar *src, *dst;\n \tlong size;\n-\tconst int marker_size = 7;\n \tint status, saved_style;\n \n \t/* We have to force the RCS \"merge\" style */\n@@ -104,7 +106,7 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,\n \tgit_xmerge_style = 0;\n \tstatus = ll_xdl_merge(drv_unused, result, path_unused,\n \t\t\t      orig, src1, NULL, src2, NULL,\n-\t\t\t      virtual_ancestor);\n+\t\t\t      virtual_ancestor, marker_size);\n \tgit_xmerge_style = saved_style;\n \tif (status <= 0)\n \t\treturn status;\n@@ -165,14 +167,15 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \t\t\tmmfile_t *orig,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n-\t\t\tint virtual_ancestor)\n+\t\t\tint virtual_ancestor, int marker_size)\n {\n-\tchar temp[3][50];\n+\tchar temp[4][50];\n \tstruct strbuf cmd = STRBUF_INIT;\n \tstruct strbuf_expand_dict_entry dict[] = {\n \t\t{ \"O\", temp[0] },\n \t\t{ \"A\", temp[1] },\n \t\t{ \"B\", temp[2] },\n+\t\t{ \"L\", temp[3] },\n \t\t{ NULL }\n \t};\n \tconst char *args[] = { \"sh\", \"-c\", NULL, NULL };\n@@ -187,6 +190,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tcreate_temp(orig, temp[0]);\n \tcreate_temp(src1, temp[1]);\n \tcreate_temp(src2, temp[2]);\n+\tsprintf(temp[3], \"%d\", marker_size);\n \n \tstrbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);\n \n@@ -279,6 +283,7 @@ static int read_merge_config(const char *var, const char *value, void *cb)\n \t\t *    %O - temporary file name for the merge base.\n \t\t *    %A - temporary file name for our version.\n \t\t *    %B - temporary file name for the other branches' version.\n+\t\t *    %L - conflict marker length\n \t\t *\n \t\t * The external merge driver should write the results in the\n \t\t * file named by %A, and signal that it has done with zero exit\n@@ -339,16 +344,13 @@ static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr\n \treturn &ll_merge_drv[LL_TEXT_MERGE];\n }\n \n-static const char *git_path_check_merge(const char *path)\n+static int git_path_check_merge(const char *path, struct git_attr_check check[2])\n {\n-\tstatic struct git_attr_check attr_merge_check;\n-\n-\tif (!attr_merge_check.attr)\n-\t\tattr_merge_check.attr = git_attr(\"merge\");\n-\n-\tif (git_checkattr(path, 1, &attr_merge_check))\n-\t\treturn NULL;\n-\treturn attr_merge_check.value;\n+\tif (!check[0].attr) {\n+\t\tcheck[0].attr = git_attr(\"merge\");\n+\t\tcheck[1].attr = git_attr(\"conflict-marker-size\");\n+\t}\n+\treturn git_checkattr(path, 2, check);\n }\n \n int ll_merge(mmbuffer_t *result_buf,\n@@ -358,16 +360,23 @@ int ll_merge(mmbuffer_t *result_buf,\n \t     mmfile_t *theirs, const char *their_label,\n \t     int virtual_ancestor)\n {\n-\tconst char *ll_driver_name;\n+\tstatic struct git_attr_check check[2];\n+\tconst char *ll_driver_name = NULL;\n+\tint marker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n \tconst struct ll_merge_driver *driver;\n \n-\tll_driver_name = git_path_check_merge(path);\n+\tif (!git_path_check_merge(path, check)) {\n+\t\tll_driver_name = check[0].value;\n+\t\tif (check[1].value) {\n+\t\t\tmarker_size = atoi(check[1].value);\n+\t\t\tif (marker_size <= 0)\n+\t\t\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n+\t\t}\n+\t}\n \tdriver = find_ll_merge_driver(ll_driver_name);\n-\n \tif (virtual_ancestor && driver->recursive)\n \t\tdriver = find_ll_merge_driver(driver->recursive);\n-\treturn driver->fn(driver, result_buf, path,\n-\t\t\t  ancestor,\n-\t\t\t  ours, our_label,\n-\t\t\t  theirs, their_label, virtual_ancestor);\n+\treturn driver->fn(driver, result_buf, path, ancestor,\n+\t\t\t  ours, our_label, theirs, their_label,\n+\t\t\t  virtual_ancestor, marker_size);\n }\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131931","messageId":"1263721144-18605-8-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 7/8] rerere: prepare for customizable conflict marker length","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:39:03Z","receivedAt":"2010-01-17T09:39:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This still uses the hardcoded conflict marker length of 7 but otherwise\nprepares the codepath to deal with customized marker length.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n rerere.c |   51 +++++++++++++++++++++++++++++++++++++++++----------\n 1 files changed, 41 insertions(+), 10 deletions(-)\n\ndiff --git a/rerere.c b/rerere.c\nindex 5b8ebcb..d4d1507 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -98,6 +98,25 @@ static void rerere_io_putstr(const char *str, struct rerere_io *io)\n \t\tferr_puts(str, io->output, &io->wrerror);\n }\n \n+static void rerere_io_putconflict(int ch, int size, struct rerere_io *io)\n+{\n+\tchar buf[64];\n+\n+\twhile (size) {\n+\t\tif (size + 2 < sizeof(buf)) {\n+\t\t\tmemset(buf, ch, size);\n+\t\t\tbuf[size] = '\\n';\n+\t\t\tbuf[size + 1] = '\\0';\n+\t\t\tsize = 0;\n+\t\t} else {\n+\t\t\tmemset(buf, ch, sizeof(buf) - 1);\n+\t\t\tbuf[sizeof(buf) - 1] = '\\0';\n+\t\t\tsize -= sizeof(buf) - 1;\n+\t\t}\n+\t\trerere_io_putstr(buf, io);\n+\t}\n+}\n+\n static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io)\n {\n \tif (io->output)\n@@ -115,7 +134,17 @@ static int rerere_file_getline(struct strbuf *sb, struct rerere_io *io_)\n \treturn strbuf_getwholeline(sb, io->input, '\\n');\n }\n \n-static int handle_path(unsigned char *sha1, struct rerere_io *io)\n+static int is_cmarker(char *buf, int marker_char, int marker_size, int want_sp)\n+{\n+\twhile (marker_size--)\n+\t\tif (*buf++ != marker_char)\n+\t\t\treturn 0;\n+\tif (want_sp && *buf != ' ')\n+\t\treturn 0;\n+\treturn isspace(*buf);\n+}\n+\n+static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)\n {\n \tgit_SHA_CTX ctx;\n \tint hunk_no = 0;\n@@ -129,30 +158,30 @@ static int handle_path(unsigned char *sha1, struct rerere_io *io)\n \t\tgit_SHA1_Init(&ctx);\n \n \twhile (!io->getline(&buf, io)) {\n-\t\tif (!prefixcmp(buf.buf, \"<<<<<<< \")) {\n+\t\tif (is_cmarker(buf.buf, '<', marker_size, 1)) {\n \t\t\tif (hunk != RR_CONTEXT)\n \t\t\t\tgoto bad;\n \t\t\thunk = RR_SIDE_1;\n-\t\t} else if (!prefixcmp(buf.buf, \"|||||||\") && isspace(buf.buf[7])) {\n+\t\t} else if (is_cmarker(buf.buf, '|', marker_size, 0)) {\n \t\t\tif (hunk != RR_SIDE_1)\n \t\t\t\tgoto bad;\n \t\t\thunk = RR_ORIGINAL;\n-\t\t} else if (!prefixcmp(buf.buf, \"=======\") && isspace(buf.buf[7])) {\n+\t\t} else if (is_cmarker(buf.buf, '=', marker_size, 0)) {\n \t\t\tif (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)\n \t\t\t\tgoto bad;\n \t\t\thunk = RR_SIDE_2;\n-\t\t} else if (!prefixcmp(buf.buf, \">>>>>>> \")) {\n+\t\t} else if (is_cmarker(buf.buf, '>', marker_size, 1)) {\n \t\t\tif (hunk != RR_SIDE_2)\n \t\t\t\tgoto bad;\n \t\t\tif (strbuf_cmp(&one, &two) > 0)\n \t\t\t\tstrbuf_swap(&one, &two);\n \t\t\thunk_no++;\n \t\t\thunk = RR_CONTEXT;\n-\t\t\trerere_io_putstr(\"<<<<<<<\\n\", io);\n+\t\t\trerere_io_putconflict('<', marker_size, io);\n \t\t\trerere_io_putmem(one.buf, one.len, io);\n-\t\t\trerere_io_putstr(\"=======\\n\", io);\n+\t\t\trerere_io_putconflict('=', marker_size, io);\n \t\t\trerere_io_putmem(two.buf, two.len, io);\n-\t\t\trerere_io_putstr(\">>>>>>>\\n\", io);\n+\t\t\trerere_io_putconflict('>', marker_size, io);\n \t\t\tif (sha1) {\n \t\t\t\tgit_SHA1_Update(&ctx, one.buf ? one.buf : \"\",\n \t\t\t\t\t    one.len + 1);\n@@ -189,6 +218,7 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output\n {\n \tint hunk_no = 0;\n \tstruct rerere_io_file io;\n+\tint marker_size = 7;\n \n \tmemset(&io, 0, sizeof(io));\n \tio.io.getline = rerere_file_getline;\n@@ -205,7 +235,7 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output\n \t\t}\n \t}\n \n-\thunk_no = handle_path(sha1, (struct rerere_io *)&io);\n+\thunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);\n \n \tfclose(io.input);\n \tif (io.io.wrerror)\n@@ -255,6 +285,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu\n \tstruct cache_entry *ce;\n \tint pos, len, i, hunk_no;\n \tstruct rerere_io_mem io;\n+\tint marker_size = 7;\n \n \t/*\n \t * Reproduce the conflicted merge in-core\n@@ -299,7 +330,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu\n \tstrbuf_init(&io.input, 0);\n \tstrbuf_attach(&io.input, result.ptr, result.size, result.size);\n \n-\thunk_no = handle_path(sha1, (struct rerere_io *)&io);\n+\thunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);\n \tstrbuf_release(&io.input);\n \tif (io.io.output)\n \t\tfclose(io.io.output);\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131932","messageId":"1263721144-18605-9-git-send-email-gitster@pobox.com","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"[PATCH 8/8] rerere: honor conflict-marker-size attribute","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T09:39:04Z","receivedAt":"2010-01-17T09:39:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n ll-merge.c |   15 +++++++++++++++\n ll-merge.h |    2 ++\n rerere.c   |    5 +++--\n 3 files changed, 20 insertions(+), 2 deletions(-)\n\ndiff --git a/ll-merge.c b/ll-merge.c\nindex d682071..0dcaae0 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -380,3 +380,18 @@ int ll_merge(mmbuffer_t *result_buf,\n \t\t\t  ours, our_label, theirs, their_label,\n \t\t\t  virtual_ancestor, marker_size);\n }\n+\n+int ll_merge_marker_size(const char *path)\n+{\n+\tstatic struct git_attr_check check;\n+\tint marker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n+\n+\tif (!check.attr)\n+\t\tcheck.attr = git_attr(\"conflict-marker-size\");\n+\tif (!git_checkattr(path, 1, &check) && check.value) {\n+\t\tmarker_size = atoi(check.value);\n+\t\tif (marker_size <= 0)\n+\t\t\tmarker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n+\t}\n+\treturn marker_size;\n+}\ndiff --git a/ll-merge.h b/ll-merge.h\nindex 5388422..ff5d84a 100644\n--- a/ll-merge.h\n+++ b/ll-merge.h\n@@ -12,4 +12,6 @@ int ll_merge(mmbuffer_t *result_buf,\n \t     mmfile_t *theirs, const char *their_label,\n \t     int virtual_ancestor);\n \n+int ll_merge_marker_size(const char *path);\n+\n #endif\ndiff --git a/rerere.c b/rerere.c\nindex d4d1507..2a2bd23 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -5,6 +5,7 @@\n #include \"dir.h\"\n #include \"resolve-undo.h\"\n #include \"ll-merge.h\"\n+#include \"attr.h\"\n \n /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */\n static int rerere_enabled = -1;\n@@ -218,7 +219,7 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output\n {\n \tint hunk_no = 0;\n \tstruct rerere_io_file io;\n-\tint marker_size = 7;\n+\tint marker_size = ll_merge_marker_size(path);\n \n \tmemset(&io, 0, sizeof(io));\n \tio.io.getline = rerere_file_getline;\n@@ -285,7 +286,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu\n \tstruct cache_entry *ce;\n \tint pos, len, i, hunk_no;\n \tstruct rerere_io_mem io;\n-\tint marker_size = 7;\n+\tint marker_size = ll_merge_marker_size(path);\n \n \t/*\n \t * Reproduce the conflicted merge in-core\n-- \n1.6.6.405.g80ed6.dirty\n"},{"id":"131938","messageId":"7vaawd82pj.fsf@alter.siamese.dyndns.org","threadId":"22256","inReplyTo":"1263721144-18605-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 0/8] Rescuing repeated merge of Documentation/git-merge.txt","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T10:07:04Z","receivedAt":"2010-01-17T10:07:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"7th one of the series has a minor nit; I fixed it up before pushing it out\nto 'pu'.\n"},{"id":"131941","messageId":"201001171252.38826.j6t@kdbg.org","threadId":"22256","inReplyTo":"1263721144-18605-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 5/8] rerere: use ll_merge() instead of using xdl_merge()","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-01-17T11:52:38Z","receivedAt":"2010-01-17T11:52:38Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Sonntag, 17. Januar 2010, Junio C Hamano wrote:\n> This allows us to pay attention to the attribute settings and custom\n> merge driver the user sets up.\n\nI do not think that this change is necessary; I even think that it is wrong, \nin particular, custom merge drivers should *not* be used anymore.\n\nThe code path is about merging the changes between preimage and postimage into \na file that has conflict markers (thisimage). At the time when this happens, \nall three images have already been processed by the custom merge driver.\n\nConsider this preimage:\n\n<foo><bar>\n<<<<<<<\n</bar>\n=======\n<baz>\ntext\n</baz></bar>\n>>>>>>>\n<more text=\"here\" />\n</foo>\n\nand a custom XML merge driver. With your change, you expect that the merge \ndriver knows how to treat syntactically incorrect XML (the \"<<<<<<<\" \nand \">>>>>>>\").\n\nOf course, without this change, we do expect that the postimage has \npractically everything outside the conflict markers unchanged[*], otherwise \nthe ll_merge() will fail.\n\nBut so would a custom XML driver that does not know how to read conflict \nmarkers.\n\n[*] Which is perhaps an assumption that is easily violated. For example, the \nXML editor used to resolve the conflict could have inserted line-breaks at \ncompletely different spots than in the conflicted preimage.\n\n-- Hannes\n"},{"id":"131954","messageId":"7v4omk8sjg.fsf@alter.siamese.dyndns.org","threadId":"22256","inReplyTo":"201001171252.38826.j6t@kdbg.org","subject":"Re: [PATCH 5/8] rerere: use ll_merge() instead of using xdl_merge()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-17T19:01:23Z","receivedAt":"2010-01-17T19:01:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> On Sonntag, 17. Januar 2010, Junio C Hamano wrote:\n>> This allows us to pay attention to the attribute settings and custom\n>> merge driver the user sets up.\n>\n> I do not think that this change is necessary; I even think that it is wrong, \n> in particular, custom merge drivers should *not* be used anymore.\n\nYou are right in that nothing is strictly necessary as long as there are\nother ways to do so.  This does not have to be how the issue is solved,\nbut I found this to be one and the most natural way to allow rerere to pay\nattention to per-path conflict marker length attribute.\n\nContents that you would want to use custom merge drivers would not benefit\nfrom the current rerere that uses the default textual merge. In your\ncustomized XML merge editor example, the merged contents have irrelevant\nline breaks on either side of the merge that break textual merge (and that\nis the reason you are using a custom XML aware merge script to begin with).\n\nSo I didn't think using ll_merge() makes things worse, and that was the\nreason why I did it this way.\n\nBut I admit I didn't think things through (and that is why your name was\non the Cc: line).  If you really want to forbid custom merge drivers, I\nthink we can add an option to ll_merge() to specify which attribute to\nignore, and force the default textual merge in the codepath, or we can go\nback to the xdl_merge() but pass a custom conflict marker length in\nxmparam_t, as a follow-up fix.\n"},{"id":"131965","messageId":"201001172140.13802.j6t@kdbg.org","threadId":"22256","inReplyTo":"7v4omk8sjg.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 5/8] rerere: use ll_merge() instead of using xdl_merge()","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2010-01-17T20:40:13Z","receivedAt":"2010-01-17T20:40:13Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Sonntag, 17. Januar 2010, Junio C Hamano wrote:\n> So I didn't think using ll_merge() makes things worse, and that was the\n> reason why I did it this way.\n\nThinking a bit more about it, the problematic point is not that a custom merge \ndriver is used, but it is the way how conflicts are marked. For example, it \nseems a bit strange that an XML merge driver would mark-up conflicts using \n<<<<<<< and >>>>>>> in random points of XML text, when it knows that the \nresult would be invalid XML (and subsequently an XML editor could fail to \nparse the result). It would be more apropriate when it used a different way \nto mark conflicts.\n\nThe conclusion is that your approach goes in the right direction. But since \nthe result depends on the traditional conflict markers, it keeps rerere tied \nto the standard text merge driver. The capability that rerere will use custom \nmerge drivers is of little use (unless the merge driver uses standard \nconflict markers); that it allows attributes for the standard text merge, is, \nof course, a plus.\n\n-- Hannes\n"}]}