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