{"thread":{"id":"23046","subject":"[PATCH v2 0/16] Add label for common ancestor to conflictstyle=diff3","startedAt":"2010-03-17T11:36:55Z","lastAt":"2010-03-20T22:47:36Z","messageCount":23,"participants":["Jonathan Nieder","Bert Wesarg","Stephen Boyd"],"isPatch":true,"patchVersion":2,"patchTotal":16},"messages":[{"id":"136996","messageId":"20100317113655.GA25470@progeny.tock","threadId":"23046","inReplyTo":null,"subject":"[PATCH v2 0/16] Add label for common ancestor to conflictstyle=diff3","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T11:36:55Z","receivedAt":"2010-03-17T11:36:55Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi all,\n\nThis is a more polished version of a series I sent a couple of days\nago [1].  Thanks to Junio for some helpful advice.\n\nThe purpose: When outputting diff3-style conflict hunks, this patch\nseries adds a label for the common ancestor (like diff3 -m would):\n\n <<<<<<< ours\n Text from the current branch\n ||||||| base\n Text from the merge base\n =======\n Text from the remote branch\n >>>>>>> theirs\n\nApparently, without this label, smerge-mode.el found in emacs 22 and\nlater has trouble parsing the conflict hunks created by git with\nmerge.conflictstyle=diff3.  More importantly, humans can sometimes use a\nreminder of what the ancestor represents, especially in cases like\ncherry-pick and revert.\n\nAs before, the bad news is that sometimes the labels for the ancestor\nare kind of pointless, as in “merged common ancestors” for\nmerge-recursive.  I am not planning to improve this.  I’d be thrilled if\nsomeone changes it to something like “merge of ac76d, 8d7ca9, and\n81873”.\n\nThe good news is a couple of new tests thrown in.  All the other changes\nI can remember are detailed in the comments after each patch (probably\nmissing some, since I haven’t started using git notes for this).\n\nI think the series is ready to receive wider exposure.  Please let me\nknow if you run into any problems when trying it out.  I would also be\nglad to hear thoughts about the details of its behavior and\nimplementation.\n\nThe series is based against master.  There are a few small conflicts\nwith next, but nothing major; I’ll point out the few that I remember\nas I go.\n\nEnjoy,\nJonathan Nieder (16):\n  xdl_merge(): add optional ancestor label to diff3-style output\n  xdl_merge(): move file1 and file2 labels to xmparam structure\n  merge-file --diff3: add a label for ancestor\n  ll_merge(): add ancestor label parameter for diff3-style output\n  checkout --conflict=diff3: add a label for ancestor\n  merge_file(): add comment explaining behavior wrt conflict style\n  merge_trees(): add ancestor label parameter for diff3-style output\n  tests: document format of conflicts from checkout -m\n  checkout -m --conflict=diff3: add a label for ancestor\n  tests: document cherry-pick behavior in face of conflicts\n  revert_or_cherry_pick(): get oneline_body from get_oneline()\n  compat: add mempcpy()\n  revert: simplify get_oneline() using mempcpy\n  revert: clarify label on conflict hunks\n  cherry-pick: add a label for ancestor\n  merge-recursive: add a label for ancestor\n\n builtin/checkout.c              |    3 +-\n builtin/merge-file.c            |    7 +-\n builtin/revert.c                |   33 ++++---\n git-compat-util.h               |    9 ++\n ll-merge.c                      |   28 +++---\n ll-merge.h                      |    2 +-\n merge-file.c                    |    8 ++-\n merge-recursive.c               |   12 ++-\n merge-recursive.h               |    1 +\n rerere.c                        |    4 +-\n t/t3507-cherry-pick-conflict.sh |  198 +++++++++++++++++++++++++++++++++++++++\n t/t6023-merge-file.sh           |    2 +-\n t/t7201-co.sh                   |   69 ++++++++++++-\n xdiff/xdiff.h                   |    6 +-\n xdiff/xmerge.c                  |   29 ++++--\n 15 files changed, 358 insertions(+), 53 deletions(-)\n create mode 100644 t/t3507-cherry-pick-conflict.sh\n\n[1] http://thread.gmane.org/gmane.linux.debian.devel.bugs.general/680778/focus=142176\n"},{"id":"136998","messageId":"20100317114653.GA25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 01/16] xdl_merge(): add optional ancestor label to diff3-style output","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T11:46:54Z","receivedAt":"2010-03-17T11:46:54Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"The ‘git checkout --conflict=diff3’ command can be used to\npresent conflicts hunks including text from the common ancestor:\n\n\t<<<<<<< ours\n\tourside\n\t|||||||\n\toriginal\n\t=======\n\ttheirside\n\t>>>>>>> theirs\n\nThe added information is helpful for resolving merges by hand, and\nmerge tools can usually grok it because it is very similar to the\noutput from diff3 -m.\n\nA subtle change can help more tools to understand the output.  ‘diff3’\nincludes the name of the merge base on the ||||||| line of the output,\nand some tools misparse the conflict hunks without it.  Add a new\nxmp->ancestor parameter to xdl_merge() for use with conflict style\nXDL_MERGE_DIFF3 as a label on the ||||||| line for any conflict hunks.\n\nIf xmp->ancestor is NULL, the output format is unchanged.\n‘git checkout’ and other users within git all use NULL for this\nparameter, so this change only provides unexposed plumbing for a fix:\nit does not affect the outward behavior of git in any way.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nAside from the commit message, the only change from v1 is\n\n -\tconst char *ancestor;\n +\tconst char *ancestor;   /* label for orig */\n\n xdiff/xdiff.h  |    1 +\n xdiff/xmerge.c |   16 ++++++++++++++--\n 2 files changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 3f6229e..fd89b9a 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -117,6 +117,7 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n typedef struct s_xmparam {\n \txpparam_t xpp;\n \tint marker_size;\n+\tconst char *ancestor;\t/* label for orig */\n } xmparam_t;\n \n #define DEFAULT_CONFLICT_MARKER_SIZE 7\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 8cbe45e..3a0ae14 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -144,11 +144,13 @@ static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)\n \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      const char *name3,\n \t\t\t      int size, int i, int style,\n \t\t\t      xdmerge_t *m, char *dest, int marker_size)\n {\n \tint marker1_size = (name1 ? strlen(name1) + 1 : 0);\n \tint marker2_size = (name2 ? strlen(name2) + 1 : 0);\n+\tint marker3_size = (name3 ? strlen(name3) + 1 : 0);\n \tint j;\n \n \tif (marker_size <= 0)\n@@ -178,10 +180,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,\n \tif (style == XDL_MERGE_DIFF3) {\n \t\t/* Shared preimage */\n \t\tif (!dest) {\n-\t\t\tsize += marker_size + 1;\n+\t\t\tsize += marker_size + 1 + marker3_size;\n \t\t} else {\n \t\t\tfor (j = 0; j < marker_size; j++)\n \t\t\t\tdest[size++] = '|';\n+\t\t\tif (marker3_size) {\n+\t\t\t\tdest[size] = ' ';\n+\t\t\t\tmemcpy(dest + size + 1, name3, marker3_size - 1);\n+\t\t\t\tsize += marker3_size;\n+\t\t\t}\n \t\t\tdest[size++] = '\\n';\n \t\t}\n \t\tsize += xdl_orig_copy(xe1, m->i0, m->chg0, 1,\n@@ -216,6 +223,7 @@ 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 const char *ancestor_name,\n \t\t\t\t int favor,\n \t\t\t\t xdmerge_t *m, char *dest, int style,\n \t\t\t\t int marker_size)\n@@ -228,6 +236,7 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,\n \n \t\tif (m->mode == 0)\n \t\t\tsize = fill_conflict_hunk(xe1, name1, xe2, name2,\n+\t\t\t\t\t\t  ancestor_name,\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@@ -397,6 +406,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t\tint flags, xmparam_t const *xmp, mmbuffer_t *result) {\n \txdmerge_t *changes, *c;\n \txpparam_t const *xpp = &xmp->xpp;\n+\tconst char * const ancestor_name = xmp->ancestor;\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@@ -534,6 +544,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\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\t\t\t\t ancestor_name,\n \t\t\t\t\t\t favor, changes, NULL, style,\n \t\t\t\t\t\t marker_size);\n \t\tresult->ptr = xdl_malloc(size);\n@@ -542,7 +553,8 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t\t\treturn -1;\n \t\t}\n \t\tresult->size = size;\n-\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2, favor, changes,\n+\t\txdl_fill_merge_buffer(xe1, name1, xe2, name2,\n+\t\t\t\t      ancestor_name, favor, changes,\n \t\t\t\t      result->ptr, style, marker_size);\n \t}\n \treturn xdl_cleanup_merge(changes);\n-- \n1.7.0\n"},{"id":"136999","messageId":"20100317115316.GB25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 02/16] xdl_merge(): move file1 and file2 labels to xmparam structure","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T11:53:16Z","receivedAt":"2010-03-17T11:53:16Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"The labels for the three participants in a potential conflict are all\noptional arguments for the xdiff merge routine; if they are NULL, then\nxdl_merge() can cope by omitting the labels from its output.  Move\nthem to the xmparam structure to allow new callers to save some\nkeystrokes where they are not needed.\n\nThis also has the virtue of making the xdiff merge interface more\nsimilar to merge_trees, which might make it easier to learn.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nThanks to Junio for the idea.  I was worried for a moment that\nthis might be a step in the wrong direction: aren’t all existing\nxmparam_t members the sort of thing that would be the same over\nmultiple merges?  That is true but not really relevant.\n\nThis has interactions of the “nonconflicting changes on adjacent lines”\nkind with commit 560119b (refactor merge flags into xmparam_t,\n2010-03-01) in next.\n\n builtin/merge-file.c |    6 ++++--\n ll-merge.c           |    8 ++++----\n xdiff/xdiff.h        |    5 +++--\n xdiff/xmerge.c       |   13 +++++++------\n 4 files changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex 1e70073..ade1e8b 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -72,8 +72,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t\t\targv[i]);\n \t}\n \n-\tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xmp, XDL_MERGE_FLAGS(level, style, favor), &result);\n+\txmp.file1 = names[0];\n+\txmp.file2 = names[2];\n+\tret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp,\n+\t\t\tXDL_MERGE_FLAGS(level, style, favor), &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 4c7f11b..b8e8971 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -83,10 +83,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\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-\t\t\t &xmp, XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, style, favor),\n+\txmp.file1 = name1;\n+\txmp.file2 = name2;\n+\treturn xdl_merge(orig, src1, src2, &xmp,\n+\t\t\t XDL_MERGE_FLAGS(XDL_MERGE_ZEALOUS, style, favor),\n \t\t\t result);\n }\n \ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex fd89b9a..82d7fc7 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -118,12 +118,13 @@ typedef struct s_xmparam {\n \txpparam_t xpp;\n \tint marker_size;\n \tconst char *ancestor;\t/* label for orig */\n+\tconst char *file1;\t/* label for mf1 */\n+\tconst char *file2;\t/* label for mf2 */\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+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,\n \t\txmparam_t const *xmp, int flags, mmbuffer_t *result);\n \n #ifdef __cplusplus\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 3a0ae14..241f7ba 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -401,12 +401,14 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,\n  *\n  * returns < 0 on error, == 0 for no conflicts, else number of conflicts\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+static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,\n+\t\txdfenv_t *xe2, xdchange_t *xscr2,\n \t\tint flags, xmparam_t const *xmp, mmbuffer_t *result) {\n \txdmerge_t *changes, *c;\n \txpparam_t const *xpp = &xmp->xpp;\n \tconst char * const ancestor_name = xmp->ancestor;\n+\tconst char * const name1 = xmp->file1;\n+\tconst char * const name2 = xmp->file2;\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@@ -560,8 +562,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \treturn xdl_cleanup_merge(changes);\n }\n \n-int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n-\t\tmmfile_t *mf2, const char *name2,\n+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,\n \t\txmparam_t const *xmp, int flags, mmbuffer_t *result) {\n \txdchange_t *xscr1, *xscr2;\n \txdfenv_t xe1, xe2;\n@@ -597,8 +598,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,\n \t\tmemcpy(result->ptr, mf1->ptr, mf1->size);\n \t\tresult->size = mf1->size;\n \t} else {\n-\t\tstatus = xdl_do_merge(&xe1, xscr1, name1,\n-\t\t\t\t      &xe2, xscr2, name2,\n+\t\tstatus = xdl_do_merge(&xe1, xscr1,\n+\t\t\t\t      &xe2, xscr2,\n \t\t\t\t      flags, xmp, result);\n \t}\n \txdl_free_script(xscr1);\n-- \n1.7.0\n"},{"id":"137000","messageId":"20100317115731.GC25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 03/16] merge-file --diff3: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T11:57:31Z","receivedAt":"2010-03-17T11:57:31Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git merge-file --diff3 can be used to present conflicts hunks\nincluding text from the common ancestor.\n\nThe added information is helpful for resolving a merge by hand, and\nmerge tools can usually grok it because it looks like output from\ndiff3 -m.  However, ‘diff3’ includes a label for the merge base on the\n||||||| line and some tools cannot parse conflict hunks without such a\nlabel.  Write the base-name as passed in a -L option (or the name of\nthe ancestor file by default) on that line.\n\ngit rerere will not have trouble parsing this output, since instead of\nlooking for a newline, it looks for whitespace after the |||||||\nmarker.  Since rerere includes its own code for recreating conflict\nhunks, conflict identifiers are unaffected.  No other code in git tries\nto parse conflict hunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nt/t6023-merge-files.sh needs another change when merging to next.\n\n@@ -225,7 +225,7 @@ et nihil mihi deerit;\n\n In loco pascuae ibi me collocavit;\n super aquam refectionis educavit me.\n-||||||||||\n+|||||||||| new5.txt\n et nihil mihi deerit.\n In loco pascuae ibi me collocavit,\n super aquam refectionis educavit me;\n\n builtin/merge-file.c  |    1 +\n t/t6023-merge-file.sh |    2 +-\n 2 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex ade1e8b..04cb67a 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -72,6 +72,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t\t\t\t\targv[i]);\n \t}\n \n+\txmp.ancestor = names[1];\n \txmp.file1 = names[0];\n \txmp.file2 = names[2];\n \tret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp,\ndiff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh\nindex d605024..16c3c69 100755\n--- a/t/t6023-merge-file.sh\n+++ b/t/t6023-merge-file.sh\n@@ -181,7 +181,7 @@ et nihil mihi deerit;\n \n In loco pascuae ibi me collocavit;\n super aquam refectionis educavit me.\n-|||||||\n+||||||| new5.txt\n et nihil mihi deerit.\n In loco pascuae ibi me collocavit,\n super aquam refectionis educavit me;\n-- \n1.7.0\n"},{"id":"137001","messageId":"20100317120321.GD25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 04/16] ll_merge(): add ancestor label parameter for diff3-style output","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:03:21Z","receivedAt":"2010-03-17T12:03:21Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Various commands using the ll_merge() function present conflict hunks\nin output something like what ‘diff3 -m’ produces if the\nmerge.conflictstyle configuration option is set to diff3.  The output\nleaves out the name of the merge base on the ||||||| line of the\noutput, and some tools misparse the conflict hunks without that.\n\nAdd a new ancestor_label parameter to ll_merge() to give callers the\npower to rectify this situation.  All callers pass NULL for now to\navoid distracting changes in outward behavior when testing this\ninterface change.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nchange from v1:\n\n --- b/ll-merge.c\n +++ b/ll-merge.c\n @@ -108,7 +108,7 @@ static int ll_union_merge(const struct ll_merge_dr\n\n  \tsaved_style = git_xmerge_style;\n        git_xmerge_style = 0;\n        status = ll_xdl_merge(drv_unused, result, path_unused,\n -                             orig, orig_name, src1, NULL, src2, NULL,\n +                             orig, NULL, src1, NULL, src2, NULL,\n                              flag, marker_size);\n        git_xmerge_style = saved_style;\n        if (status <= 0)\n\nThere is no possibility of a diff3-style merge in that codepath.\n\n builtin/checkout.c |    2 +-\n ll-merge.c         |   20 +++++++++++---------\n ll-merge.h         |    2 +-\n merge-file.c       |    2 +-\n merge-recursive.c  |    2 +-\n rerere.c           |    4 ++--\n 6 files changed, 17 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acefaaf..d67f809 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state)\n \tread_mmblob(&ours, active_cache[pos+1]->sha1);\n \tread_mmblob(&theirs, active_cache[pos+2]->sha1);\n \n-\tstatus = ll_merge(&result_buf, path, &ancestor,\n+\tstatus = ll_merge(&result_buf, path, &ancestor, NULL,\n \t\t\t  &ours, \"ours\", &theirs, \"theirs\", 0);\n \tfree(ancestor.ptr);\n \tfree(ours.ptr);\ndiff --git a/ll-merge.c b/ll-merge.c\nindex b8e8971..92670af 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -15,7 +15,7 @@ struct ll_merge_driver;\n typedef int (*ll_merge_fn)(const struct ll_merge_driver *,\n \t\t\t   mmbuffer_t *result,\n \t\t\t   const char *path,\n-\t\t\t   mmfile_t *orig,\n+\t\t\t   mmfile_t *orig, const char *orig_name,\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 flag,\n@@ -36,7 +36,7 @@ struct ll_merge_driver {\n static int ll_binary_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t   mmbuffer_t *result,\n \t\t\t   const char *path_unused,\n-\t\t\t   mmfile_t *orig,\n+\t\t\t   mmfile_t *orig, const char *orig_name,\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 flag, int marker_size)\n@@ -57,7 +57,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,\n static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\tmmbuffer_t *result,\n \t\t\tconst char *path,\n-\t\t\tmmfile_t *orig,\n+\t\t\tmmfile_t *orig, const char *orig_name,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n \t\t\tint flag, int marker_size)\n@@ -73,7 +73,8 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\t\tpath, name1, name2);\n \t\treturn ll_binary_merge(drv_unused, result,\n \t\t\t\t       path,\n-\t\t\t\t       orig, src1, name1,\n+\t\t\t\t       orig, orig_name,\n+\t\t\t\t       src1, name1,\n \t\t\t\t       src2, name2,\n \t\t\t\t       flag, marker_size);\n \t}\n@@ -83,6 +84,7 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n \t\tstyle = git_xmerge_style;\n \tif (marker_size > 0)\n \t\txmp.marker_size = marker_size;\n+\txmp.ancestor = orig_name;\n \txmp.file1 = name1;\n \txmp.file2 = name2;\n \treturn xdl_merge(orig, src1, src2, &xmp,\n@@ -93,7 +95,7 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,\n static int ll_union_merge(const struct ll_merge_driver *drv_unused,\n \t\t\t  mmbuffer_t *result,\n \t\t\t  const char *path_unused,\n-\t\t\t  mmfile_t *orig,\n+\t\t\t  mmfile_t *orig, const char *orig_name,\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 flag, int marker_size)\n@@ -106,7 +108,7 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,\n \tsaved_style = git_xmerge_style;\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      orig, NULL, src1, NULL, src2, NULL,\n \t\t\t      flag, marker_size);\n \tgit_xmerge_style = saved_style;\n \tif (status <= 0)\n@@ -165,7 +167,7 @@ static void create_temp(mmfile_t *src, char *path)\n static int ll_ext_merge(const struct ll_merge_driver *fn,\n \t\t\tmmbuffer_t *result,\n \t\t\tconst char *path,\n-\t\t\tmmfile_t *orig,\n+\t\t\tmmfile_t *orig, const char *orig_name,\n \t\t\tmmfile_t *src1, const char *name1,\n \t\t\tmmfile_t *src2, const char *name2,\n \t\t\tint flag, int marker_size)\n@@ -356,7 +358,7 @@ static int git_path_check_merge(const char *path, struct git_attr_check check[2]\n \n int ll_merge(mmbuffer_t *result_buf,\n \t     const char *path,\n-\t     mmfile_t *ancestor,\n+\t     mmfile_t *ancestor, const char *ancestor_label,\n \t     mmfile_t *ours, const char *our_label,\n \t     mmfile_t *theirs, const char *their_label,\n \t     int flag)\n@@ -378,7 +380,7 @@ int ll_merge(mmbuffer_t *result_buf,\n \tdriver = find_ll_merge_driver(ll_driver_name);\n \tif (virtual_ancestor && driver->recursive)\n \t\tdriver = find_ll_merge_driver(driver->recursive);\n-\treturn driver->fn(driver, result_buf, path, ancestor,\n+\treturn driver->fn(driver, result_buf, path, ancestor, ancestor_label,\n \t\t\t  ours, our_label, theirs, their_label,\n \t\t\t  flag, marker_size);\n }\ndiff --git a/ll-merge.h b/ll-merge.h\nindex 5788922..57754cc 100644\n--- a/ll-merge.h\n+++ b/ll-merge.h\n@@ -7,7 +7,7 @@\n \n int ll_merge(mmbuffer_t *result_buf,\n \t     const char *path,\n-\t     mmfile_t *ancestor,\n+\t     mmfile_t *ancestor, const char *ancestor_label,\n \t     mmfile_t *ours, const char *our_label,\n \t     mmfile_t *theirs, const char *their_label,\n \t     int flag);\ndiff --git a/merge-file.c b/merge-file.c\nindex fd34d76..07cc0c9 100644\n--- a/merge-file.c\n+++ b/merge-file.c\n@@ -30,7 +30,7 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our\n \tint merge_status;\n \tmmbuffer_t res;\n \n-\tmerge_status = ll_merge(&res, path, base,\n+\tmerge_status = ll_merge(&res, path, base, NULL,\n \t\t\t\tour, \".our\", their, \".their\", 0);\n \tif (merge_status < 0)\n \t\treturn NULL;\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 195ebf9..3b2cc9d 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -640,7 +640,7 @@ static int merge_3way(struct merge_options *o,\n \tread_mmblob(&src1, a->sha1);\n \tread_mmblob(&src2, b->sha1);\n \n-\tmerge_status = ll_merge(result_buf, a->path, &orig,\n+\tmerge_status = ll_merge(result_buf, a->path, &orig, NULL,\n \t\t\t\t&src1, name1, &src2, name2,\n \t\t\t\t(!!o->call_depth) | (favor << 1));\n \ndiff --git a/rerere.c b/rerere.c\nindex a59f74f..f221bed 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -319,7 +319,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu\n \t\tif (!mmfile[i].ptr && !mmfile[i].size)\n \t\t\tmmfile[i].ptr = xstrdup(\"\");\n \t}\n-\tll_merge(&result, path, &mmfile[0],\n+\tll_merge(&result, path, &mmfile[0], NULL,\n \t\t &mmfile[1], \"ours\",\n \t\t &mmfile[2], \"theirs\", 0);\n \tfor (i = 0; i < 3; i++)\n@@ -376,7 +376,7 @@ static int merge(const char *name, const char *path)\n \t\tret = 1;\n \t\tgoto out;\n \t}\n-\tret = ll_merge(&result, path, &base, &cur, \"\", &other, \"\", 0);\n+\tret = ll_merge(&result, path, &base, NULL, &cur, \"\", &other, \"\", 0);\n \tif (!ret) {\n \t\tFILE *f = fopen(path, \"w\");\n \t\tif (!f)\n-- \n1.7.0\n"},{"id":"137002","messageId":"20100317120459.GE25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 05/16] checkout --conflict=diff3: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:04:59Z","receivedAt":"2010-03-17T12:04:59Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git checkout --conflict=diff3 can be used to present conflicts hunks\nincluding text from the common ancestor:\n\n\t<<<<<<< ours\n\tourside\n\t|||||||\n\toriginal\n\t=======\n\ttheirside\n\t>>>>>>> theirs\n\nThe added information is helpful for resolving a merge by hand, and\nmerge tools can usually understand it without trouble because it looks\nlike output from ‘diff3 -m’.\n\nUnfortunately, not all can: diff3 includes a label for the merge base\non the ||||||| line and it seems some tools cannot parse conflict\nhunks without such a label.  Humans could use help in interpreting the\noutput, too.  So mark the start of the text from the common ancestor\nwith the label “||||||| base”.\n\ngit rerere’s conflict identifiers are not affected: to parse conflict\nhunks, rerere looks for whitespace after the ||||||| marker rather\nthan a newline, and to compute preimage ids, rerere has its own code\nfor creating conflict hunks.  No other code in git tries to parse\nconflict hunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nLabel changed.  Thanks for the feedback.\n\n builtin/checkout.c |    2 +-\n t/t7201-co.sh      |    4 ++--\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex d67f809..d652b4c 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state)\n \tread_mmblob(&ours, active_cache[pos+1]->sha1);\n \tread_mmblob(&theirs, active_cache[pos+2]->sha1);\n \n-\tstatus = ll_merge(&result_buf, path, &ancestor, NULL,\n+\tstatus = ll_merge(&result_buf, path, &ancestor, \"base\",\n \t\t\t  &ours, \"ours\", &theirs, \"theirs\", 0);\n \tfree(ancestor.ptr);\n \tfree(ours.ptr);\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex d20ed61..981ae8f 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -481,7 +481,7 @@ test_expect_success 'checkout with --merge, in diff3 -m style' '\n \t(\n \t\techo \"<<<<<<< ours\"\n \t\techo ourside\n-\t\techo \"|||||||\"\n+\t\techo \"||||||| base\"\n \t\techo original\n \t\techo \"=======\"\n \t\techo theirside\n@@ -525,7 +525,7 @@ test_expect_success 'checkout --conflict=diff3' '\n \t(\n \t\techo \"<<<<<<< ours\"\n \t\techo ourside\n-\t\techo \"|||||||\"\n+\t\techo \"||||||| base\"\n \t\techo original\n \t\techo \"=======\"\n \t\techo theirside\n-- \n1.7.0\n"},{"id":"137003","messageId":"20100317120545.GF25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 06/16] merge_file(): add comment explaining behavior wrt conflict style","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:05:46Z","receivedAt":"2010-03-17T12:05:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"The merge_file() function is a helper for ‘git read-tree’, which does\nnot respect the merge.conflictstyle option, so there is no need to\nworry about what ancestor_name it should pass to ll_merge().  Add a\ncomment to this effect.\n\nSigned-off-by: Jonathan Nieder <jrnieder@mgila.com>\n---\n\n merge-file.c |    6 ++++++\n 1 files changed, 6 insertions(+), 0 deletions(-)\n\ndiff --git a/merge-file.c b/merge-file.c\nindex 07cc0c9..c336c93 100644\n--- a/merge-file.c\n+++ b/merge-file.c\n@@ -30,6 +30,12 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our\n \tint merge_status;\n \tmmbuffer_t res;\n \n+\t/*\n+\t * This function is only used by cmd_merge_tree, which\n+\t * does not respect the merge.conflictstyle option.\n+\t * There is no need to worry about a label for the\n+\t * common ancestor.\n+\t */\n \tmerge_status = ll_merge(&res, path, base, NULL,\n \t\t\t\tour, \".our\", their, \".their\", 0);\n \tif (merge_status < 0)\n-- \n1.7.0\n"},{"id":"137004","messageId":"20100317120829.GG25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 07/16] merge_trees(): add ancestor label parameter for diff3-style output","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:08:29Z","receivedAt":"2010-03-17T12:08:29Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Commands using the merge_trees() machinery will present conflict hunks\nin output something like what ‘diff3 -m’ produces if the\nmerge.conflictstyle configuration option is set to diff3.  The output\nlacks the name of the merge base on the ||||||| line of the output,\nand tools can misparse the conflict hunks without it.  Add a new\no->ancestor parameter to merge_trees() for use as a label for the\nancestor in conflict hunks.\n\nIf o->ancestor is NULL, the output format is as before.  All callers\npass NULL, so this patch does not affect the outward behavior of git.\n\nIf o->ancestor is non-NULL and both branches renamed the base file\nto the same name, that name is included in the conflict hunk labels.\nEven if o->ancestor is NULL I think this would be a good change, but\nthis patch only does it in the non-NULL case to ensure the output\nformat does not change where it might matter.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nOnly the commit message was changed.\n\n merge-recursive.c |   11 ++++++++---\n merge-recursive.h |    1 +\n 2 files changed, 9 insertions(+), 3 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 3b2cc9d..017cafd 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -608,7 +608,7 @@ static int merge_3way(struct merge_options *o,\n \t\t      const char *branch2)\n {\n \tmmfile_t orig, src1, src2;\n-\tchar *name1, *name2;\n+\tchar *base_name, *name1, *name2;\n \tint merge_status;\n \tint favor;\n \n@@ -628,10 +628,15 @@ static int merge_3way(struct merge_options *o,\n \t\t}\n \t}\n \n-\tif (strcmp(a->path, b->path)) {\n+\tif (strcmp(a->path, b->path) ||\n+\t    (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {\n+\t\tbase_name = o->ancestor == NULL ? NULL :\n+\t\t\txstrdup(mkpath(\"%s:%s\", o->ancestor, one->path));\n \t\tname1 = xstrdup(mkpath(\"%s:%s\", branch1, a->path));\n \t\tname2 = xstrdup(mkpath(\"%s:%s\", branch2, b->path));\n \t} else {\n+\t\tbase_name = o->ancestor == NULL ? NULL :\n+\t\t\txstrdup(mkpath(\"%s\", o->ancestor));\n \t\tname1 = xstrdup(mkpath(\"%s\", branch1));\n \t\tname2 = xstrdup(mkpath(\"%s\", branch2));\n \t}\n@@ -640,7 +645,7 @@ static int merge_3way(struct merge_options *o,\n \tread_mmblob(&src1, a->sha1);\n \tread_mmblob(&src2, b->sha1);\n \n-\tmerge_status = ll_merge(result_buf, a->path, &orig, NULL,\n+\tmerge_status = ll_merge(result_buf, a->path, &orig, base_name,\n \t\t\t\t&src1, name1, &src2, name2,\n \t\t\t\t(!!o->call_depth) | (favor << 1));\n \ndiff --git a/merge-recursive.h b/merge-recursive.h\nindex be8410a..d1192f5 100644\n--- a/merge-recursive.h\n+++ b/merge-recursive.h\n@@ -4,6 +4,7 @@\n #include \"string-list.h\"\n \n struct merge_options {\n+\tconst char *ancestor;\n \tconst char *branch1;\n \tconst char *branch2;\n \tenum {\n-- \n1.7.0\n"},{"id":"137005","messageId":"20100317120939.GH25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 08/16] tests: document format of conflicts from checkout -m","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:09:39Z","receivedAt":"2010-03-17T12:09:39Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"We are about to change the format of the conflict hunks that ‘checkout\n--merge’ writes.  Add tests checking the current behavior first.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nUnchanged.\n\n t/t7201-co.sh |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 61 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 981ae8f..f3f0c4c 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -11,10 +11,12 @@ Test switching across them.\n   ! [master] Initial A one, A two\n    * [renamer] Renamer R one->uno, M two\n     ! [side] Side M one, D two, A three\n-  ---\n-    + [side] Side M one, D two, A three\n-   *  [renamer] Renamer R one->uno, M two\n-  +*+ [master] Initial A one, A two\n+     ! [simple] Simple D one, M two\n+  ----\n+     + [simple] Simple D one, M two\n+    +  [side] Side M one, D two, A three\n+   *   [renamer] Renamer R one->uno, M two\n+  +*++ [master] Initial A one, A two\n \n '\n \n@@ -52,6 +54,11 @@ test_expect_success setup '\n \tgit update-index --add --remove one two three &&\n \tgit commit -m \"Side M one, D two, A three\" &&\n \n+\tgit checkout -b simple master &&\n+\trm -f one &&\n+\tfill a c e > two &&\n+\tgit commit -a -m \"Simple D one, M two\" &&\n+\n \tgit checkout master\n '\n \n@@ -166,6 +173,56 @@ test_expect_success 'checkout -m with merge conflict' '\n \t! test -s current\n '\n \n+test_expect_success 'format of merge conflict from checkout -m' '\n+\n+\tgit checkout -f master && git clean -f &&\n+\n+\tfill b d > two &&\n+\tgit checkout -m simple &&\n+\n+\tgit ls-files >current &&\n+\tfill same two two two >expect &&\n+\ttest_cmp current expect &&\n+\n+\tcat <<-EOF >expect &&\n+\t<<<<<<< simple\n+\ta\n+\tc\n+\te\n+\t=======\n+\tb\n+\td\n+\t>>>>>>> local\n+\tEOF\n+\ttest_cmp two expect\n+'\n+\n+test_expect_success 'checkout --merge --conflict=diff3 <branch>' '\n+\n+\tgit checkout -f master && git reset --hard && git clean -f &&\n+\n+\tfill b d > two &&\n+\tgit checkout --merge --conflict=diff3 simple &&\n+\n+\tcat <<-EOF >expect &&\n+\t<<<<<<< simple\n+\ta\n+\tc\n+\te\n+\t|||||||\n+\ta\n+\tb\n+\tc\n+\td\n+\te\n+\t=======\n+\tb\n+\td\n+\t>>>>>>> local\n+\tEOF\n+\ttest_cmp two expect\n+'\n+\n test_expect_success 'checkout to detach HEAD (with advice declined)' '\n \n \tgit config advice.detachedHead false &&\n-- \n1.7.0\n"},{"id":"137006","messageId":"20100317121325.GI25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 09/16] checkout -m --conflict=diff3: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:13:25Z","receivedAt":"2010-03-17T12:13:25Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git checkout --merge --conflict=diff3 can be used to present conflict\nhunks including text from the common ancestor.  The added information\ncan be helpful for resolving a merge by hand, and merge tools tend to\nunderstand it because it is very similar to what ‘diff3 -m’ produces.\n\nUnlike current git, diff3 -m includes a label for the merge base on\nthe ||||||| line, and unfortunately, some tools cannot parse the\nconflict hunks without it.  Humans can benefit from a cue when\nlearning to interpreting the format, too.  Mark the start of the text\nfrom the old branch with a label based on the branch’s name.\n\ngit rerere does not have trouble parsing this output and its preimage\nids are unchanged since it includes its own code for recreating\nconflict hunks.  No other code in git tries to parse conflict hunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nUnchanged.\n\n builtin/checkout.c |    1 +\n t/t7201-co.sh      |    2 +-\n 2 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex d652b4c..88b1f43 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t\t\tret = reset_tree(new->commit->tree, opts, 1);\n \t\t\tif (ret)\n \t\t\t\treturn ret;\n+\t\t\to.ancestor = old->name;\n \t\t\to.branch1 = new->name;\n \t\t\to.branch2 = \"local\";\n \t\t\tmerge_trees(&o, new->commit->tree, work,\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex f3f0c4c..1337fa5 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -209,7 +209,7 @@ test_expect_success 'checkout --merge --conflict=diff3 <branch>' '\n \ta\n \tc\n \te\n-\t|||||||\n+\t||||||| master\n \ta\n \tb\n \tc\n-- \n1.7.0\n"},{"id":"137007","messageId":"20100317121354.GJ25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 10/16] tests: document cherry-pick behavior in face of conflicts","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:13:54Z","receivedAt":"2010-03-17T12:13:54Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"We are about to change the format of the conflict hunks that\ncherry-pick and revert write.  Add tests checking the current behavior\nfirst.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n t/t3507-cherry-pick-conflict.sh |  198 +++++++++++++++++++++++++++++++++++++++\n 1 files changed, 198 insertions(+), 0 deletions(-)\n create mode 100644 t/t3507-cherry-pick-conflict.sh\n\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nnew file mode 100644\nindex 0000000..e856356\n--- /dev/null\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -0,0 +1,198 @@\n+#!/bin/sh\n+\n+test_description='test cherry-pick and revert with conflicts\n+\n+  -\n+  + picked: rewrites foo to c\n+  + base: rewrites foo to b\n+  + initial: writes foo as a, unrelated as unrelated\n+\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\n+\techo unrelated >unrelated &&\n+\tgit add unrelated &&\n+\ttest_commit initial foo a &&\n+\ttest_commit base foo b &&\n+\ttest_commit picked foo c &&\n+\tgit config advice.detachedhead false\n+\n+'\n+\n+test_expect_success 'failed cherry-pick does not advance HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick picked &&\n+\tnewhead=$(git rev-parse HEAD) &&\n+\n+\ttest \"$head\" = \"$newhead\"\n+'\n+\n+test_expect_success 'failed cherry-pick produces dirty index' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\n+\ttest_must_fail git update-index --refresh -q &&\n+\ttest_must_fail git diff-index --exit-code HEAD\n+'\n+\n+test_expect_success 'failed cherry-pick registers participants in index' '\n+\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\t{\n+\t\tgit checkout base -- foo &&\n+\t\tgit ls-files --stage foo &&\n+\t\tgit checkout initial -- foo &&\n+\t\tgit ls-files --stage foo &&\n+\t\tgit checkout picked -- foo &&\n+\t\tgit ls-files --stage foo\n+\t} > stages &&\n+\tsed \"\n+\t\t1 s/ 0\t/ 1\t/\n+\t\t2 s/ 0\t/ 2\t/\n+\t\t3 s/ 0\t/ 3\t/\n+\t\" < stages > expected &&\n+\tgit checkout -f initial^0 &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\tgit ls-files --stage --unmerged > actual &&\n+\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'failed cherry-pick describes conflict in work tree' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\tcat <<-EOF > expected &&\n+\t<<<<<<< HEAD\n+\ta\n+\t=======\n+\tc\n+\t>>>>>>> objid picked\n+\tEOF\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\n+\tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'diff3 -m style' '\n+\n+\tgit config merge.conflictstyle diff3 &&\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\tcat <<-EOF > expected &&\n+\t<<<<<<< HEAD\n+\ta\n+\t|||||||\n+\tb\n+\t=======\n+\tc\n+\t>>>>>>> objid picked\n+\tEOF\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\n+\tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'revert also handles conflicts sanely' '\n+\n+\tgit config --unset merge.conflictstyle &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\tcat <<-EOF > expected &&\n+\t<<<<<<< HEAD\n+\ta\n+\t=======\n+\tb\n+\t>>>>>>> objid picked\n+\tEOF\n+\t{\n+\t\tgit checkout picked -- foo &&\n+\t\tgit ls-files --stage foo &&\n+\t\tgit checkout initial -- foo &&\n+\t\tgit ls-files --stage foo &&\n+\t\tgit checkout base -- foo &&\n+\t\tgit ls-files --stage foo\n+\t} > stages &&\n+\tsed \"\n+\t\t1 s/ 0\t/ 1\t/\n+\t\t2 s/ 0\t/ 2\t/\n+\t\t3 s/ 0\t/ 3\t/\n+\t\" < stages > expected-stages &&\n+\tgit checkout -f initial^0 &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git revert picked &&\n+\tnewhead=$(git rev-parse HEAD) &&\n+\tgit ls-files --stage --unmerged > actual-stages &&\n+\n+\ttest \"$head\" = \"$newhead\" &&\n+\ttest_must_fail git update-index --refresh -q &&\n+\ttest_must_fail git diff-index --exit-code HEAD &&\n+\ttest_cmp expected-stages actual-stages &&\n+\tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'revert conflict, diff3 -m style' '\n+\tgit config merge.conflictstyle diff3 &&\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\tcat <<-EOF > expected &&\n+\t<<<<<<< HEAD\n+\ta\n+\t|||||||\n+\tc\n+\t=======\n+\tb\n+\t>>>>>>> objid picked\n+\tEOF\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git revert picked &&\n+\n+\tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\n-- \n1.7.0\n"},{"id":"137008","messageId":"20100317121546.GK25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 11/16] revert_or_cherry_pick(): get oneline_body from get_oneline()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:15:46Z","receivedAt":"2010-03-17T12:15:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Currently the one-line commit message for the cherry-picked commit\nis found with strchr(get_oneline(), ' ').  That wastes a few CPU\ncycles, and more importantly, it makes it difficult to tweak the\noutput from get_oneline() later.  Teach get_oneline() to store the\none-line commit message using a caller-supplied pointer to avoid these\nproblems.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nMaybe the next few patches should be squashed.  They are separated one\ncommit per idea, but they affect the same code.\n\n builtin/revert.c |   11 +++++------\n 1 files changed, 5 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex eff5268..4b2042f 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -73,7 +73,7 @@ static void parse_args(int argc, const char **argv)\n \t\texit(1);\n }\n \n-static char *get_oneline(const char *message)\n+static char *get_oneline(const char *message, char **body)\n {\n \tchar *result;\n \tconst char *p = message, *abbrev, *eol;\n@@ -99,6 +99,7 @@ static char *get_oneline(const char *message)\n \tmemcpy(result + abbrev_len, \"... \", 4);\n \tmemcpy(result + abbrev_len + 4, p, oneline_len);\n \tresult[abbrev_len + 4 + oneline_len] = '\\0';\n+\t*body = result + abbrev_len + 4;\n \treturn result;\n }\n \n@@ -249,7 +250,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n \tint i, index_fd, clean;\n-\tchar *oneline, *reencoded_message = NULL;\n+\tchar *oneline, *oneline_body, *reencoded_message = NULL;\n \tconst char *message, *encoding;\n \tchar *defmsg = git_pathdup(\"MERGE_MSG\");\n \tstruct merge_options o;\n@@ -341,15 +342,13 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\t\t\t\tgit_commit_encoding, encoding)))\n \t\tmessage = reencoded_message;\n \n-\toneline = get_oneline(message);\n+\toneline = get_oneline(message, &oneline_body);\n \n \tif (action == REVERT) {\n-\t\tchar *oneline_body = strchr(oneline, ' ');\n-\n \t\tbase = commit;\n \t\tnext = parent;\n \t\tadd_to_msg(\"Revert \\\"\");\n-\t\tadd_to_msg(oneline_body + 1);\n+\t\tadd_to_msg(oneline_body);\n \t\tadd_to_msg(\"\\\"\\n\\nThis reverts commit \");\n \t\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n \n-- \n1.7.0\n"},{"id":"137009","messageId":"20100317121623.GL25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 12/16] compat: add mempcpy()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:16:23Z","receivedAt":"2010-03-17T12:16:23Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"The mempcpy() function was added in glibc 2.1.  It is quite handy, so\nadd an implementation for cross-platform use.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n git-compat-util.h |    9 +++++++++\n 1 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex a3c4537..9bed5a0 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -331,6 +331,7 @@ extern int git_vsnprintf(char *str, size_t maxsize,\n #ifdef __GLIBC_PREREQ\n #if __GLIBC_PREREQ(2, 1)\n #define HAVE_STRCHRNUL\n+#define HAVE_MEMPCPY\n #endif\n #endif\n \n@@ -344,6 +345,14 @@ static inline char *gitstrchrnul(const char *s, int c)\n }\n #endif\n \n+#ifndef HAVE_MEMPCPY\n+#define mempcpy gitmempcpy\n+static inline void *gitmempcpy(void *dest, const void *src, size_t n)\n+{\n+\treturn (char *)memcpy(dest, src, n) + n;\n+}\n+#endif\n+\n extern void release_pack_memory(size_t, int);\n \n extern char *xstrdup(const char *str);\n-- \n1.7.0\n"},{"id":"137010","messageId":"20100317121746.GM25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 13/16] revert: simplify get_oneline() using mempcpy","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:17:46Z","receivedAt":"2010-03-17T12:17:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Avoid some pointer arithmetic and make future modifications easier by\nusing mempcpy to advance a pointer as the result is written.\n\nWhile at it, make the code more self-explanatory by using strlen() on\nconstant strings.  GCC will compute the length at compile time; I am\nnot sure about other compilers, but this is not performance-critical\nanyway.  It should be simple to add a conststrlen() macro later if\nneeded.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n builtin/revert.c |   13 ++++++-------\n 1 files changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4b2042f..6a47655 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -75,7 +75,7 @@ static void parse_args(int argc, const char **argv)\n \n static char *get_oneline(const char *message, char **body)\n {\n-\tchar *result;\n+\tchar *result, *q;\n \tconst char *p = message, *abbrev, *eol;\n \tint abbrev_len, oneline_len;\n \n@@ -94,12 +94,11 @@ static char *get_oneline(const char *message, char **body)\n \tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n \tabbrev_len = strlen(abbrev);\n \toneline_len = eol - p;\n-\tresult = xmalloc(abbrev_len + 5 + oneline_len);\n-\tmemcpy(result, abbrev, abbrev_len);\n-\tmemcpy(result + abbrev_len, \"... \", 4);\n-\tmemcpy(result + abbrev_len + 4, p, oneline_len);\n-\tresult[abbrev_len + 4 + oneline_len] = '\\0';\n-\t*body = result + abbrev_len + 4;\n+\tq = result = xmalloc(abbrev_len + strlen(\"... \") + oneline_len + 1);\n+\tq = mempcpy(q, abbrev, abbrev_len);\n+\t*body = q = mempcpy(q, \"... \", strlen(\"... \"));\n+\tq = mempcpy(q, p, oneline_len);\n+\t*q = '\\0';\n \treturn result;\n }\n \n-- \n1.7.0\n"},{"id":"137011","messageId":"20100317121938.GN25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 14/16] revert: clarify label on conflict hunks","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:19:38Z","receivedAt":"2010-03-17T12:19:38Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"When reverting a commit, the commit being merged is not the commit\nto revert itself but its parent.  Clarify the text in conflict\nhunks to explain this.\n\nExample:\n\n\t<<<<<<< HEAD\n\tSomething old.\n\tSomething new.\n\tSomething blue.\n\t=======\n\tSomething old.\n\tSomething rotten.\n\tSomething blue.\n\t>>>>>>> parent of ac789a9... Remove rotten line\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nNew patch: a small fix.\n\n builtin/revert.c                |   14 +++++++++-----\n t/t3507-cherry-pick-conflict.sh |    4 ++--\n 2 files changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 6a47655..56f2947 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -73,11 +73,11 @@ static void parse_args(int argc, const char **argv)\n \t\texit(1);\n }\n \n-static char *get_oneline(const char *message, char **body)\n+static char *get_oneline(const char *message, int revert, char **body)\n {\n \tchar *result, *q;\n-\tconst char *p = message, *abbrev, *eol;\n-\tint abbrev_len, oneline_len;\n+\tconst char *p = message, *prefix, *abbrev, *eol;\n+\tint prefix_len, abbrev_len, oneline_len;\n \n \tif (!p)\n \t\tdie (\"Could not read commit message of %s\",\n@@ -91,10 +91,14 @@ static char *get_oneline(const char *message, char **body)\n \t\t\t; /* do nothing */\n \t} else\n \t\teol = p;\n+\tprefix = revert ? \"parent of \" : \"\";\n+\tprefix_len = revert ? strlen(\"parent of \") : 0;\n \tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n \tabbrev_len = strlen(abbrev);\n \toneline_len = eol - p;\n-\tq = result = xmalloc(abbrev_len + strlen(\"... \") + oneline_len + 1);\n+\tq = result = xmalloc(prefix_len + abbrev_len +\n+\t\t\t     strlen(\"... \") + oneline_len + 1);\n+\tq = mempcpy(q, prefix, prefix_len);\n \tq = mempcpy(q, abbrev, abbrev_len);\n \t*body = q = mempcpy(q, \"... \", strlen(\"... \"));\n \tq = mempcpy(q, p, oneline_len);\n@@ -341,7 +345,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\t\t\t\tgit_commit_encoding, encoding)))\n \t\tmessage = reencoded_message;\n \n-\toneline = get_oneline(message, &oneline_body);\n+\toneline = get_oneline(message, action == REVERT, &oneline_body);\n \n \tif (action == REVERT) {\n \t\tbase = commit;\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex e856356..6a20817 100644\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -138,7 +138,7 @@ test_expect_success 'revert also handles conflicts sanely' '\n \ta\n \t=======\n \tb\n-\t>>>>>>> objid picked\n+\t>>>>>>> parent of objid picked\n \tEOF\n \t{\n \t\tgit checkout picked -- foo &&\n@@ -183,7 +183,7 @@ test_expect_success 'revert conflict, diff3 -m style' '\n \tc\n \t=======\n \tb\n-\t>>>>>>> objid picked\n+\t>>>>>>> parent of objid picked\n \tEOF\n \n \tgit update-index --refresh &&\n-- \n1.7.0\n"},{"id":"137012","messageId":"20100317122314.GO25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 15/16] cherry-pick: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:23:14Z","receivedAt":"2010-03-17T12:23:14Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git cherry-pick and git revert will write conflict hunks something\nlike what ‘diff3 -m’ produces if the merge.conflictstyle configuration\noption is set to diff3.  Unlike ‘diff3 -m’, though, the output lacks a\nlabel for the merge base on the ||||||| line of the output.\n\nSome tools can misparse the conflict hunks without such a label.\nEspecially in a cherry-pick, humans parsing the conflict hunks by hand\nmight want to know what the common ancestor represents, too.  Add a\nlabel.\n\nExample:\n\n\t<<<<<<< HEAD\n\tSomething old.\n\tSomething new.\n\tSomething rotten.\n\tSomething blue.\n\t||||||| parent of 387924c... Remove something rotten\n\tSomething old.\n\tSomething rotten.\n\tSomething blue.\n\t=======\n\tSomething old.\n\tsomething blue.\n\t>>>>>>> 387924c... Remove something rotten\n\ngit rerere does not have trouble parsing the new output, and its\npreimage ids are unchanged since it includes its own code for\nrecreating conflict hunks.  No other code in git parses conflict\nhunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nHopefully the new labels clearer, especially when reverting a commit.\nThoughts?\n\n builtin/revert.c                |   27 ++++++++++++++++-----------\n t/t3507-cherry-pick-conflict.sh |    4 ++--\n 2 files changed, 18 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 56f2947..7a39b52 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -73,11 +73,11 @@ static void parse_args(int argc, const char **argv)\n \t\texit(1);\n }\n \n-static char *get_oneline(const char *message, int revert, char **body)\n+static char *get_oneline(const char *message, char **body, char **parent)\n {\n \tchar *result, *q;\n-\tconst char *p = message, *prefix, *abbrev, *eol;\n-\tint prefix_len, abbrev_len, oneline_len;\n+\tconst char *p = message, *abbrev, *eol;\n+\tint abbrev_len, oneline_len;\n \n \tif (!p)\n \t\tdie (\"Could not read commit message of %s\",\n@@ -91,14 +91,12 @@ static char *get_oneline(const char *message, int revert, char **body)\n \t\t\t; /* do nothing */\n \t} else\n \t\teol = p;\n-\tprefix = revert ? \"parent of \" : \"\";\n-\tprefix_len = revert ? strlen(\"parent of \") : 0;\n \tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n \tabbrev_len = strlen(abbrev);\n \toneline_len = eol - p;\n-\tq = result = xmalloc(prefix_len + abbrev_len +\n-\t\t\t     strlen(\"... \") + oneline_len + 1);\n-\tq = mempcpy(q, prefix, prefix_len);\n+\t*parent = q = xmalloc(strlen(\"parent of \") + abbrev_len +\n+\t\t\t      strlen(\"... \") + oneline_len + 1);\n+\tresult = q = mempcpy(q, \"parent of \", strlen(\"parent of \"));\n \tq = mempcpy(q, abbrev, abbrev_len);\n \t*body = q = mempcpy(q, \"... \", strlen(\"... \"));\n \tq = mempcpy(q, p, oneline_len);\n@@ -252,8 +250,10 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n+\tconst char *base_label, *next_label;\n \tint i, index_fd, clean;\n-\tchar *oneline, *oneline_body, *reencoded_message = NULL;\n+\tchar *oneline, *oneline_body, *parent_label;\n+\tchar *reencoded_message = NULL;\n \tconst char *message, *encoding;\n \tchar *defmsg = git_pathdup(\"MERGE_MSG\");\n \tstruct merge_options o;\n@@ -345,11 +345,13 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\t\t\t\tgit_commit_encoding, encoding)))\n \t\tmessage = reencoded_message;\n \n-\toneline = get_oneline(message, action == REVERT, &oneline_body);\n+\toneline = get_oneline(message, &oneline_body, &parent_label);\n \n \tif (action == REVERT) {\n \t\tbase = commit;\n+\t\tbase_label = oneline;\n \t\tnext = parent;\n+\t\tnext_label = parent_label;\n \t\tadd_to_msg(\"Revert \\\"\");\n \t\tadd_to_msg(oneline_body);\n \t\tadd_to_msg(\"\\\"\\n\\nThis reverts commit \");\n@@ -362,7 +364,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\tadd_to_msg(\".\\n\");\n \t} else {\n \t\tbase = parent;\n+\t\tbase_label = parent_label;\n \t\tnext = commit;\n+\t\tnext_label = oneline;\n \t\tset_author_ident_env(message);\n \t\tadd_message_to_msg(message);\n \t\tif (no_replay) {\n@@ -374,8 +378,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \n \tread_cache();\n \tinit_merge_options(&o);\n+\to.ancestor = base ? base_label : \"(empty tree)\";\n \to.branch1 = \"HEAD\";\n-\to.branch2 = oneline;\n+\to.branch2 = next ? next_label : \"(empty tree)\";\n \n \thead_tree = parse_tree_indirect(head);\n \tnext_tree = next ? next->tree : empty_tree();\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex 6a20817..e25cf80 100644\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -112,7 +112,7 @@ test_expect_success 'diff3 -m style' '\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n-\t|||||||\n+\t||||||| parent of objid picked\n \tb\n \t=======\n \tc\n@@ -179,7 +179,7 @@ test_expect_success 'revert conflict, diff3 -m style' '\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n-\t|||||||\n+\t||||||| objid picked\n \tc\n \t=======\n \tb\n-- \n1.7.0\n"},{"id":"137013","messageId":"20100317122653.GP25641@progeny.tock","threadId":"23046","inReplyTo":"20100317113655.GA25470@progeny.tock","subject":"[PATCH 16/16] merge-recursive: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-17T12:26:53Z","receivedAt":"2010-03-17T12:26:53Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git merge-recursive (and hence git merge) will present conflict hunks\nin output something like what ‘diff3 -m’ produces if the\nmerge.conflictstyle configuration option is set to diff3.\nThere is a small difference from diff3: diff3 -m includes a label\nfor the merge base on the ||||||| line.\n\nTools familiar with the format and humans unfamiliar with the format\ndo a better job with a label.  Mark the start of the text from the\nmerge bases with the heading \"||||||| merged common ancestors\".\n\nIt would be nicer to use a more informative label.  Perhaps someone\nwill provide one some day.\n\ngit rerere does not have trouble parsing the new output, and its\npreimage ids are unchanged since it has its own code for re-creating\nconflict hunks.  No other code in git parses conflict hunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nAs before.\n\nThat’s all.  I hope you enjoyed the patches and that the added\ncomplication for the new cherry-pick messages was not too unpleasant to\nlook at.\n\nGood night,\nJonathan\n\n merge-recursive.c |    1 +\n 1 files changed, 1 insertions(+), 0 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 017cafd..917397c 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -1347,6 +1347,7 @@ int merge_recursive(struct merge_options *o,\n \tif (!o->call_depth)\n \t\tread_cache();\n \n+\to->ancestor = \"merged common ancestors\";\n \tclean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,\n \t\t\t    &mrtree);\n \n-- \n1.7.0\n"},{"id":"137015","messageId":"36ca99e91003170722m6642ca5q93b2669feaf3dea2@mail.gmail.com","threadId":"23046","inReplyTo":"20100317114653.GA25641@progeny.tock","subject":"Re: [PATCH 01/16] xdl_merge(): add optional ancestor label to diff3-style output","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2010-03-17T14:22:52Z","receivedAt":"2010-03-17T14:22:52Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"On Wed, Mar 17, 2010 at 12:46, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\n> index 8cbe45e..3a0ae14 100644\n> --- a/xdiff/xmerge.c\n> +++ b/xdiff/xmerge.c\n> @@ -397,6 +406,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n>                int flags, xmparam_t const *xmp, mmbuffer_t *result) {\n>        xdmerge_t *changes, *c;\n>        xpparam_t const *xpp = &xmp->xpp;\n> +       const char * const ancestor_name = xmp->ancestor;\n\nStyle. * should be aligned to the variable name.\n\n>        int i0, i1, i2, chg0, chg1, chg2;\n>        int level = flags & XDL_MERGE_LEVEL_MASK;\n>        int style = flags & XDL_MERGE_STYLE_MASK;\n\nFWIW:\n\n    Acked-by: Bert Wesarg <Bert.Wesarg@googlemail.com>\n"},{"id":"137059","messageId":"780e0a6b1003171309k75b33d3cpb4b1c6370d67942f@mail.gmail.com","threadId":"23046","inReplyTo":"20100317121546.GK25641@progeny.tock","subject":"Re: [PATCH 11/16] revert_or_cherry_pick(): get oneline_body from get_oneline()","fromName":"Stephen Boyd","fromEmail":"bebarino@gmail.com","sentAt":"2010-03-17T20:09:55Z","receivedAt":"2010-03-17T20:09:55Z","isPatch":true,"sender":{"key":"bebarino@gmail.com","avatar":"https://avatars.githubusercontent.com/u/38832?v=4"},"body":"On Wed, Mar 17, 2010 at 5:15 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n>\n> Maybe the next few patches should be squashed.  They are separated one\n> commit per idea, but they affect the same code.\n>\n\nCould all this code just use the custom format printing routines in\npretty.c? It might not be super efficient but at least it wouldn't\nduplicate a bunch of code.\n"},{"id":"137069","messageId":"20100318031638.GA18193@progeny.tock","threadId":"23046","inReplyTo":"780e0a6b1003171309k75b33d3cpb4b1c6370d67942f@mail.gmail.com","subject":"Re: [PATCH 11/16] revert_or_cherry_pick(): get oneline_body from get_oneline()","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-18T03:16:38Z","receivedAt":"2010-03-18T03:16:38Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Stephen Boyd wrote:\n\n> Could all this code just use the custom format printing routines in\n> pretty.c? It might not be super efficient but at least it wouldn't\n> duplicate a bunch of code.\n\nI like this idea, but I wasn’t able to pull it off.  You see,\ncmd_revert() uses a few substrings from a single string it generates:\n\n parent of ca87ef9... Do something very imporant\n ^         ^          ^\n 1         2          3\n\nThese are put together like so:\n\nFor the commit message:\n\n Subject: Revert \"[3]Do something very important\"\n\n This reverts commit ca87ef90000000000000000000000000000000000.\n\nFor the conflict markers:\n\n <<<<<<< HEAD\n Version from the tip of the current branch.\n ||||||| [2]ca87ef9... Do something very important\n Version from the commit to be reverted.\n =======\n Version from the parent of the commit to be reverted.\n >>>>>>> [1]parent of ca87ef9... Do something very important\n\nNevertheless, investigating it did spur me to simplify this part of the\nseries a little.  I think the following two patches could replace\npatches 11, 13, 14, and 15 from this thread.  I do not want to do any\ndrastic refactoring without libifying this code, though, and that should\nwait for another series, I think.\n\nThanks for the feedback.\n\nJonathan Nieder (2):\n  revert: clarify label on conflict hunks\n  cherry-pick, revert: add a label for ancestor\n\n builtin/revert.c                |  129 +++++++++++++++++++++++----------------\n t/t3507-cherry-pick-conflict.sh |    8 +-\n 2 files changed, 80 insertions(+), 57 deletions(-)\n"},{"id":"137070","messageId":"20100318033316.GB18193@progeny.tock","threadId":"23046","inReplyTo":"20100318031638.GA18193@progeny.tock","subject":"[PATCH 11,13,14 v2] revert: clarify label on conflict hunks","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-18T03:33:17Z","receivedAt":"2010-03-18T03:33:17Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"When reverting a commit, the commit being merged is not the commit\nto revert itself but its parent.  Clarify the text in conflict\nhunks to explain this.\n\nExample:\n\n\t<<<<<<< HEAD\n\tSomething old.\n\tSomething new.\n\tSomething blue.\n\t=======\n\tSomething old.\n\tSomething rotten.\n\tSomething blue.\n\t>>>>>>> parent of ac789a9... Remove rotten line\n\nAlso free a temporary buffer that was not freed before.  This is not\nimportant because it is a small one-time allocation.  It would become a\nmemory leak if unnoticed when libifying cherry-pick.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nThis rearranges the code a little to make it easier to read and\nmanipulate.\n\n builtin/revert.c                |  100 ++++++++++++++++++++++++---------------\n t/t3507-cherry-pick-conflict.sh |    4 +-\n 2 files changed, 63 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex eff5268..b314629 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -45,6 +45,8 @@ static const char *me;\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n+static char *get_encoding(const char *message);\n+\n static void parse_args(int argc, const char **argv)\n {\n \tconst char * const * usage_str =\n@@ -73,33 +75,63 @@ static void parse_args(int argc, const char **argv)\n \t\texit(1);\n }\n \n-static char *get_oneline(const char *message)\n+struct commit_message {\n+\tchar *parent_label;\n+\tconst char *label;\n+\tconst char *subject;\n+\tchar *reencoded_message;\n+\tconst char *message;\n+};\n+\n+static int get_message(const char *raw_message, struct commit_message *out)\n {\n-\tchar *result;\n-\tconst char *p = message, *abbrev, *eol;\n+\tconst char *encoding;\n+\tconst char *p, *abbrev, *eol;\n+\tchar *q;\n \tint abbrev_len, oneline_len;\n \n-\tif (!p)\n-\t\tdie (\"Could not read commit message of %s\",\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n+\tif (!raw_message)\n+\t\treturn -1;\n+\tencoding = get_encoding(raw_message);\n+\tif (!encoding)\n+\t\tencoding = \"UTF-8\";\n+\tif (!git_commit_encoding)\n+\t\tgit_commit_encoding = \"UTF-8\";\n+\tif ((out->reencoded_message = reencode_string(raw_message,\n+\t\t\t\t\tgit_commit_encoding, encoding)))\n+\t\tout->message = out->reencoded_message;\n+\n+\tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n+\tabbrev_len = strlen(abbrev);\n+\n+\t/* Find beginning and end of commit subject. */\n+\tp = out->message;\n \twhile (*p && (*p != '\\n' || p[1] != '\\n'))\n \t\tp++;\n-\n \tif (*p) {\n \t\tp += 2;\n \t\tfor (eol = p + 1; *eol && *eol != '\\n'; eol++)\n \t\t\t; /* do nothing */\n \t} else\n \t\teol = p;\n-\tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n-\tabbrev_len = strlen(abbrev);\n \toneline_len = eol - p;\n-\tresult = xmalloc(abbrev_len + 5 + oneline_len);\n-\tmemcpy(result, abbrev, abbrev_len);\n-\tmemcpy(result + abbrev_len, \"... \", 4);\n-\tmemcpy(result + abbrev_len + 4, p, oneline_len);\n-\tresult[abbrev_len + 4 + oneline_len] = '\\0';\n-\treturn result;\n+\n+\tout->parent_label = xmalloc(strlen(\"parent of \") + abbrev_len +\n+\t\t\t      strlen(\"... \") + oneline_len + 1);\n+\tq = out->parent_label;\n+\tq = mempcpy(q, \"parent of \", strlen(\"parent of \"));\n+\tout->label = q;\n+\tq = mempcpy(q, abbrev, abbrev_len);\n+\tq = mempcpy(q, \"... \", strlen(\"... \"));\n+\tout->subject = q;\n+\tq = mempcpy(q, p, oneline_len);\n+\t*q = '\\0';\n+\treturn 0;\n+}\n+\n+static void free_message(struct commit_message *msg) {\n+\tfree(msg->parent_label);\n+\tfree(msg->reencoded_message);\n }\n \n static char *get_encoding(const char *message)\n@@ -248,9 +280,10 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n+\tconst char *next_label;\n \tint i, index_fd, clean;\n-\tchar *oneline, *reencoded_message = NULL;\n-\tconst char *message, *encoding;\n+\tstruct commit_message msg = { NULL, NULL, NULL, NULL, NULL };\n+\n \tchar *defmsg = git_pathdup(\"MERGE_MSG\");\n \tstruct merge_options o;\n \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n@@ -314,14 +347,14 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \telse\n \t\tparent = commit->parents->item;\n \n-\tif (!(message = commit->buffer))\n-\t\tdie (\"Cannot get commit message for %s\",\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\n \tif (parent && parse_commit(parent) < 0)\n \t\tdie(\"%s: cannot parse parent commit %s\",\n \t\t    me, sha1_to_hex(parent->object.sha1));\n \n+\tif (get_message(commit->buffer, &msg) != 0)\n+\t\tdie (\"Cannot get commit message for %s\",\n+\t\t\t\tsha1_to_hex(commit->object.sha1));\n+\n \t/*\n \t * \"commit\" is an existing commit.  We would want to apply\n \t * the difference it introduces since its first parent \"prev\"\n@@ -332,24 +365,12 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \tmsg_fd = hold_lock_file_for_update(&msg_file, defmsg,\n \t\t\t\t\t   LOCK_DIE_ON_ERROR);\n \n-\tencoding = get_encoding(message);\n-\tif (!encoding)\n-\t\tencoding = \"UTF-8\";\n-\tif (!git_commit_encoding)\n-\t\tgit_commit_encoding = \"UTF-8\";\n-\tif ((reencoded_message = reencode_string(message,\n-\t\t\t\t\tgit_commit_encoding, encoding)))\n-\t\tmessage = reencoded_message;\n-\n-\toneline = get_oneline(message);\n-\n \tif (action == REVERT) {\n-\t\tchar *oneline_body = strchr(oneline, ' ');\n-\n \t\tbase = commit;\n \t\tnext = parent;\n+\t\tnext_label = msg.parent_label;\n \t\tadd_to_msg(\"Revert \\\"\");\n-\t\tadd_to_msg(oneline_body + 1);\n+\t\tadd_to_msg(msg.subject);\n \t\tadd_to_msg(\"\\\"\\n\\nThis reverts commit \");\n \t\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n \n@@ -361,8 +382,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t} else {\n \t\tbase = parent;\n \t\tnext = commit;\n-\t\tset_author_ident_env(message);\n-\t\tadd_message_to_msg(message);\n+\t\tnext_label = msg.label;\n+\t\tset_author_ident_env(msg.message);\n+\t\tadd_message_to_msg(msg.message);\n \t\tif (no_replay) {\n \t\t\tadd_to_msg(\"(cherry picked from commit \");\n \t\t\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n@@ -373,7 +395,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \tread_cache();\n \tinit_merge_options(&o);\n \to.branch1 = \"HEAD\";\n-\to.branch2 = oneline;\n+\to.branch2 = next ? next_label : \"(empty tree)\";\n \n \thead_tree = parse_tree_indirect(head);\n \tnext_tree = next ? next->tree : empty_tree();\n@@ -437,7 +459,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\targs[i] = NULL;\n \t\treturn execv_git_cmd(args);\n \t}\n-\tfree(reencoded_message);\n+\tfree_message(&msg);\n \tfree(defmsg);\n \n \treturn 0;\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex e856356..6a20817 100644\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -138,7 +138,7 @@ test_expect_success 'revert also handles conflicts sanely' '\n \ta\n \t=======\n \tb\n-\t>>>>>>> objid picked\n+\t>>>>>>> parent of objid picked\n \tEOF\n \t{\n \t\tgit checkout picked -- foo &&\n@@ -183,7 +183,7 @@ test_expect_success 'revert conflict, diff3 -m style' '\n \tc\n \t=======\n \tb\n-\t>>>>>>> objid picked\n+\t>>>>>>> parent of objid picked\n \tEOF\n \n \tgit update-index --refresh &&\n-- \n1.7.0\n"},{"id":"137071","messageId":"20100318033411.GC18193@progeny.tock","threadId":"23046","inReplyTo":"20100318031638.GA18193@progeny.tock","subject":"[PATCH 15/16 v2] cherry-pick, revert: add a label for ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-18T03:34:11Z","receivedAt":"2010-03-18T03:34:11Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"When writing conflict hunks in ‘diff3 -m’ format, also add a label to\nthe common ancestor.  Especially in a cherry-pick, it is not immediately\nobvious without such a label what the common ancestor represents.\n\ngit rerere does not have trouble parsing the new output and its preimage\nids are unchanged since it includes its own code for recreating conflict\nhunks.  No other code in git parses conflict hunks.\n\nRequested-by: Stefan Monnier <monnier@iro.umontreal.ca>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n builtin/revert.c                |    5 ++++-\n t/t3507-cherry-pick-conflict.sh |    4 ++--\n 2 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex b314629..625281c 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -280,7 +280,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n-\tconst char *next_label;\n+\tconst char *base_label, *next_label;\n \tint i, index_fd, clean;\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL, NULL };\n \n@@ -367,6 +367,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \n \tif (action == REVERT) {\n \t\tbase = commit;\n+\t\tbase_label = msg.label;\n \t\tnext = parent;\n \t\tnext_label = msg.parent_label;\n \t\tadd_to_msg(\"Revert \\\"\");\n@@ -381,6 +382,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\tadd_to_msg(\".\\n\");\n \t} else {\n \t\tbase = parent;\n+\t\tbase_label = msg.parent_label;\n \t\tnext = commit;\n \t\tnext_label = msg.label;\n \t\tset_author_ident_env(msg.message);\n@@ -394,6 +396,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \n \tread_cache();\n \tinit_merge_options(&o);\n+\to.ancestor = base ? base_label : \"(empty tree)\";\n \to.branch1 = \"HEAD\";\n \to.branch2 = next ? next_label : \"(empty tree)\";\n \ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex 6a20817..e25cf80 100644\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -112,7 +112,7 @@ test_expect_success 'diff3 -m style' '\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n-\t|||||||\n+\t||||||| parent of objid picked\n \tb\n \t=======\n \tc\n@@ -179,7 +179,7 @@ test_expect_success 'revert conflict, diff3 -m style' '\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n-\t|||||||\n+\t||||||| objid picked\n \tc\n \t=======\n \tb\n-- \n1.7.0\n"},{"id":"137384","messageId":"20100320224736.GC31098@progeny.tock","threadId":"23046","inReplyTo":"36ca99e91003170722m6642ca5q93b2669feaf3dea2@mail.gmail.com","subject":"Re: [PATCH 01/16] xdl_merge(): add optional ancestor label to diff3-style output","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-03-20T22:47:36Z","receivedAt":"2010-03-20T22:47:36Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Bert Wesarg wrote:\n> On Wed, Mar 17, 2010 at 12:46, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n>> --- a/xdiff/xmerge.c\n>> +++ b/xdiff/xmerge.c\n>> @@ -397,6 +406,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n>>  \tint flags, xmparam_t const *xmp, mmbuffer_t *result) {\n>>  \txdmerge_t *changes, *c;\n>>  \txpparam_t const *xpp = &xmp->xpp;\n>> +\tconst char * const ancestor_name = xmp->ancestor;\n>\n> Style. * should be aligned to the variable name.\n\nNot so clear to me:\n\n $ git grep -e '\\* const' origin/master | wc -l\n 90\n $ git grep -e '\\*const' origin/master | wc -l\n 23\n\nI do prefer the style you suggest, so I’ve fixed it.\n\n> FWIW:\n> \n>     Acked-by: Bert Wesarg <Bert.Wesarg@googlemail.com>\n\nThanks for looking it over.  I’ll be sending a rebased version in a\nmoment including your ack; I hope that’s okay.\n\nJonathan\n"}]}