Currently rerere can't handle nested conflicts and will error out when it encounters such conflicts. Do that by recursively calling the 'handle_conflict' function to normalize the conflict. The conflict ID calculation here deserves some explanation: As we are using the same handle_conflict function, the nested conflict is normalized the same way as for non-nested conflicts, which means the ancestor in the diff3 case is stripped out, and the parts of the conflict are ordered alphabetically. The conflict ID is however is only calculated in the top level handle_conflict call, so it will include the markers that 'rerere' adds to the output. e.g. say there's the following conflict: <<<<<<< HEAD 1 ======= <<<<<<< HEAD 3 ======= 2 >>>>>>> branch-2 >>>>>>> branch-3~ it would be reordered as follows in the preimage: <<<<<<< 1 ======= <<<<<<< 2 ======= 3 >>>>>>> >>>>>>> and the conflict ID would be calculated as sha1(1<NUL><<<<<<< 2 ======= 3 >>>>>>><NUL>) Stripping out vs. leaving the conflict markers in place should have no practical impact, but it simplifies the implementation. Signed-off-by: Thomas Gummerer <t.gummerer@xxxxxxxxx> --- No automated test for this yet. As mentioned in the cover letter as well, I'm not sure if this is common enough for us to actually consider this use case. I don't know how nested conflicts could actually be created apart from committing a file with conflict markers, but maybe I'm just lacking imagination, so if someone has an example for that I would be very grateful :) If we decide to do this, it probably also merits a mention in Documentation/technical/rerere.txt. rerere.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/rerere.c b/rerere.c index f3cfd1c09b..45e2bd6ff1 100644 --- a/rerere.c +++ b/rerere.c @@ -365,12 +365,18 @@ static int handle_conflict(struct strbuf *out, struct rerere_io *io, RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL } hunk = RR_SIDE_1; struct strbuf one = STRBUF_INIT, two = STRBUF_INIT; - struct strbuf buf = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT; int has_conflicts = 1; while (!io->getline(&buf, io)) { - if (is_cmarker(buf.buf, '<', marker_size)) - goto bad; - else if (is_cmarker(buf.buf, '|', marker_size)) { + if (is_cmarker(buf.buf, '<', marker_size)) { + if (handle_conflict(&conflict, io, marker_size, NULL) < 0) + goto bad; + if (hunk == RR_SIDE_1) + strbuf_addbuf(&one, &conflict); + else + strbuf_addbuf(&two, &conflict); + strbuf_release(&conflict); + } else if (is_cmarker(buf.buf, '|', marker_size)) { if (hunk != RR_SIDE_1) goto bad; hunk = RR_ORIGINAL; -- 2.17.0.588.g4d217cdf8e.dirty