Skip to content

Commit 73bcd8e

Browse files
committed
built-in add -p: coalesce hunks after splitting them
This is considered "the right thing to do", according to 933e44d ("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 <[email protected]>
1 parent 5988354 commit 73bcd8e

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

add-patch.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,48 @@ static void render_diff_header(struct add_p_state *s,
395395
}
396396
}
397397

398+
/* Coalesce hunks again that were split */
399+
static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
400+
size_t *hunk_index, struct hunk *temp)
401+
{
402+
size_t i = *hunk_index;
403+
struct hunk *hunk = file_diff->hunk + i;
404+
struct hunk_header *header = &temp->header, *next;
405+
406+
if (hunk->use != USE_HUNK)
407+
return 0;
408+
409+
memcpy(temp, hunk, sizeof(*temp));
410+
/* We simply skip the colored part (if any) when merging hunks */
411+
temp->colored_start = temp->colored_end = 0;
412+
413+
for (; i + 1 < file_diff->hunk_nr; i++) {
414+
hunk++;
415+
next = &hunk->header;
416+
417+
if (hunk->use != USE_HUNK ||
418+
header->new_offset >= next->new_offset ||
419+
header->new_offset + header->new_count < next->new_offset ||
420+
temp->start >= hunk->start ||
421+
temp->end < hunk->start)
422+
break;
423+
424+
temp->end = hunk->end;
425+
temp->colored_end = hunk->colored_end;
426+
427+
header->old_count = next->old_offset + next->old_count
428+
- header->old_offset;
429+
header->new_count = next->new_offset + next->new_count
430+
- header->new_offset;
431+
}
432+
433+
if (i == *hunk_index)
434+
return 0;
435+
436+
*hunk_index = i;
437+
return 1;
438+
}
439+
398440
static void reassemble_patch(struct add_p_state *s,
399441
struct file_diff *file_diff, struct strbuf *out)
400442
{
@@ -405,12 +447,19 @@ static void reassemble_patch(struct add_p_state *s,
405447
render_diff_header(s, file_diff, 0, out);
406448

407449
for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
450+
struct hunk temp = { 0 };
451+
408452
hunk = file_diff->hunk + i;
409453
if (hunk->use != USE_HUNK)
410454
delta += hunk->header.old_count
411455
- hunk->header.new_count;
412-
else
456+
else {
457+
/* merge overlapping hunks into a temporary hunk */
458+
if (merge_hunks(s, file_diff, &i, &temp))
459+
hunk = &temp;
460+
413461
render_hunk(s, hunk, delta, 0, out);
462+
}
414463
}
415464
}
416465

0 commit comments

Comments
 (0)