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.gumme...@gmail.com>
---

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

Reply via email to