rerere: factor out handle_conflict function

Factor out the handle_conflict function, which handles a single conflict in a path. This is in preparation for a subsequent commit, where this function will be re-used. Note that this does change the behaviour of 'git rerere' slightly. Where previously we'd consider all files where an unmatched conflict marker is found as invalid, we now only consider files invalid when the "ours" conflict marker ("<<<<<<< <text>") is unmatched, not when other conflict markers (e.g. "=======") is unmatched. Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Thomas Gummerer committed Aug 5, 2018 at 18:20 UTC c0f16f8e14432b9b6a1b21885080eab6388d887e
1 file changed +47 -40
rerere.c
+47 -40
@@ -384,85 +384,92 @@ static int is_cmarker(char *buf, int marker_char, int marker_size)
384 return isspace(*buf);
385 }
386
387 -/*
388 - * Read contents a file with conflicts, normalize the conflicts
389 - * by (1) discarding the common ancestor version in diff3-style,
390 - * (2) reordering our side and their side so that whichever sorts
391 - * alphabetically earlier comes before the other one, while
392 - * computing the "conflict ID", which is just an SHA-1 hash of
393 - * one side of the conflict, NUL, the other side of the conflict,
394 - * and NUL concatenated together.
395 - *
396 - * Return 1 if conflict hunks are found, 0 if there are no conflict
397 - * hunks and -1 if an error occured.
398 - */
399 -static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
387 +static int handle_conflict(struct rerere_io *io, int marker_size, git_SHA_CTX *ctx)
388 {
401 - git_SHA_CTX ctx;
402 - int has_conflicts = 0;
389 enum {
404 - RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL
405 - } hunk = RR_CONTEXT;
390 + RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL
391 + } hunk = RR_SIDE_1;
392 struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
393 struct strbuf buf = STRBUF_INIT;
408 -
409 - if (sha1)
410 - git_SHA1_Init(&ctx);
394 + int has_conflicts = -1;
395
396 while (!io->getline(&buf, io)) {
397 if (is_cmarker(buf.buf, '<', marker_size)) {
414 - if (hunk != RR_CONTEXT)
415 - goto bad;
416 - hunk = RR_SIDE_1;
398 + break;
399 } else if (is_cmarker(buf.buf, '|', marker_size)) {
400 if (hunk != RR_SIDE_1)
419 - goto bad;
401 + break;
402 hunk = RR_ORIGINAL;
403 } else if (is_cmarker(buf.buf, '=', marker_size)) {
404 if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)
423 - goto bad;
405 + break;
406 hunk = RR_SIDE_2;
407 } else if (is_cmarker(buf.buf, '>', marker_size)) {
408 if (hunk != RR_SIDE_2)
427 - goto bad;
409 + break;
410 if (strbuf_cmp(&one, &two) > 0)
411 strbuf_swap(&one, &two);
412 has_conflicts = 1;
431 - hunk = RR_CONTEXT;
413 rerere_io_putconflict('<', marker_size, io);
414 rerere_io_putmem(one.buf, one.len, io);
415 rerere_io_putconflict('=', marker_size, io);
416 rerere_io_putmem(two.buf, two.len, io);
417 rerere_io_putconflict('>', marker_size, io);
437 - if (sha1) {
438 - git_SHA1_Update(&ctx, one.buf ? one.buf : "",
418 + if (ctx) {
419 + git_SHA1_Update(ctx, one.buf ? one.buf : "",
420 one.len + 1);
440 - git_SHA1_Update(&ctx, two.buf ? two.buf : "",
421 + git_SHA1_Update(ctx, two.buf ? two.buf : "",
422 two.len + 1);
423 }
443 - strbuf_reset(&one);
444 - strbuf_reset(&two);
424 + break;
425 } else if (hunk == RR_SIDE_1)
426 strbuf_addbuf(&one, &buf);
427 else if (hunk == RR_ORIGINAL)
428 ; /* discard */
429 else if (hunk == RR_SIDE_2)
430 strbuf_addbuf(&two, &buf);
451 - else
452 - rerere_io_putstr(buf.buf, io);
453 - continue;
454 - bad:
455 - hunk = 99; /* force error exit */
456 - break;
431 }
432 strbuf_release(&one);
433 strbuf_release(&two);
434 strbuf_release(&buf);
435
436 + return has_conflicts;
437 +}
438 +
439 +/*
440 + * Read contents a file with conflicts, normalize the conflicts
441 + * by (1) discarding the common ancestor version in diff3-style,
442 + * (2) reordering our side and their side so that whichever sorts
443 + * alphabetically earlier comes before the other one, while
444 + * computing the "conflict ID", which is just an SHA-1 hash of
445 + * one side of the conflict, NUL, the other side of the conflict,
446 + * and NUL concatenated together.
447 + *
448 + * Return 1 if conflict hunks are found, 0 if there are no conflict
449 + * hunks and -1 if an error occured.
450 + */
451 +static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
452 +{
453 + git_SHA_CTX ctx;
454 + struct strbuf buf = STRBUF_INIT;
455 + int has_conflicts = 0;
456 + if (sha1)
457 + git_SHA1_Init(&ctx);
458 +
459 + while (!io->getline(&buf, io)) {
460 + if (is_cmarker(buf.buf, '<', marker_size)) {
461 + has_conflicts = handle_conflict(io, marker_size,
462 + sha1 ? &ctx : NULL);
463 + if (has_conflicts < 0)
464 + break;
465 + } else
466 + rerere_io_putstr(buf.buf, io);
467 + }
468 + strbuf_release(&buf);
469 +
470 if (sha1)
471 git_SHA1_Final(sha1, &ctx);
464 - if (hunk != RR_CONTEXT)
465 - return -1;
472 +
473 return has_conflicts;
474 }
475