@matheusbsbs / matheus-bagliano / commits / 11f2c0dae8
Fork 0

built-in add -p: coalesce hunks after splitting them

This is considered "the right thing to do", according to 933e44d3a0 ("add -p": work-around an old laziness that does not coalesce hunks, 2011-04-06). Note: we cannot simply modify the hunks while merging them; Once we implement hunk editing, we will call `reassemble_patch()` whenever a hunk is edited, therefore we must not modify the hunks (because the user might e.g. hit `K` and change their mind whether to stage the previous hunk). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Dec 13, 2019 at 08:07 UTC 11f2c0dae8f8889b533455d700121d437f4be19f
1 file changed +57 -1
add-patch.c
+57 -1
@@ -433,6 +433,55 @@ static void render_diff_header(struct add_p_state *s,
433 }
434 }
435
436 +/* Coalesce hunks again that were split */
437 +static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
438 + size_t *hunk_index, struct hunk *merged)
439 +{
440 + size_t i = *hunk_index;
441 + struct hunk *hunk = file_diff->hunk + i;
442 + /* `header` corresponds to the merged hunk */
443 + struct hunk_header *header = &merged->header, *next;
444 +
445 + if (hunk->use != USE_HUNK)
446 + return 0;
447 +
448 + *merged = *hunk;
449 + /* We simply skip the colored part (if any) when merging hunks */
450 + merged->colored_start = merged->colored_end = 0;
451 +
452 + for (; i + 1 < file_diff->hunk_nr; i++) {
453 + hunk++;
454 + next = &hunk->header;
455 +
456 + /*
457 + * Stop merging hunks when:
458 + *
459 + * - the hunk is not selected for use, or
460 + * - the hunk does not overlap with the already-merged hunk(s)
461 + */
462 + if (hunk->use != USE_HUNK ||
463 + header->new_offset >= next->new_offset ||
464 + header->new_offset + header->new_count < next->new_offset ||
465 + merged->start >= hunk->start ||
466 + merged->end < hunk->start)
467 + break;
468 +
469 + merged->end = hunk->end;
470 + merged->colored_end = hunk->colored_end;
471 +
472 + header->old_count = next->old_offset + next->old_count
473 + - header->old_offset;
474 + header->new_count = next->new_offset + next->new_count
475 + - header->new_offset;
476 + }
477 +
478 + if (i == *hunk_index)
479 + return 0;
480 +
481 + *hunk_index = i;
482 + return 1;
483 +}
484 +
485 static void reassemble_patch(struct add_p_state *s,
486 struct file_diff *file_diff, struct strbuf *out)
487 {
@@ -443,12 +492,19 @@ static void reassemble_patch(struct add_p_state *s,
492 render_diff_header(s, file_diff, 0, out);
493
494 for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
495 + struct hunk merged = { 0 };
496 +
497 hunk = file_diff->hunk + i;
498 if (hunk->use != USE_HUNK)
499 delta += hunk->header.old_count
500 - hunk->header.new_count;
450 - else
501 + else {
502 + /* merge overlapping hunks into a temporary hunk */
503 + if (merge_hunks(s, file_diff, &i, &merged))
504 + hunk = &merged;
505 +
506 render_hunk(s, hunk, delta, 0, out);
507 + }
508 }
509 }
510