Skip to content

Commit 2b8ea7f

Browse files
phillipwoodgitster
authored andcommitted
add -p: calculate offset delta for edited patches
Recount the number of preimage and postimage lines in a hunk after it has been edited so any change in the number of insertions or deletions can be used to adjust the offsets of subsequent hunks. If an edited hunk is subsequently split then the offset correction will be lost. It would be possible to fix this if it is a problem, however the code here is still an improvement on the status quo for the common case where an edited hunk is applied without being split. This is also a necessary step to removing '--recount' and '--allow-overlap' from the invocation of 'git apply'. Before '--recount' can be removed the splitting and coalescing counting needs to be fixed to handle a missing newline at the end of a file. In order to remove '--allow-overlap' there needs to be i) some way of verifying the offset data in the edited hunk (probably by correlating the preimage (or postimage if the patch is going to be applied in reverse) lines of the edited and unedited versions to see if they are offset or if any leading/trailing context lines have been removed) and ii) a way of dealing with edited hunks that change context lines that are shared with neighbouring hunks. Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fecc6f3 commit 2b8ea7f

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

git-add--interactive.perl

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -938,13 +938,23 @@ sub coalesce_overlapping_hunks {
938938
parse_hunk_header($text->[0]);
939939
unless ($_->{USE}) {
940940
$ofs_delta += $o_cnt - $n_cnt;
941+
# If this hunk has been edited then subtract
942+
# the delta that is due to the edit.
943+
if ($_->{OFS_DELTA}) {
944+
$ofs_delta -= $_->{OFS_DELTA};
945+
}
941946
next;
942947
}
943948
if ($ofs_delta) {
944949
$n_ofs += $ofs_delta;
945950
$_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
946951
$n_ofs, $n_cnt);
947952
}
953+
# If this hunk was edited then adjust the offset delta
954+
# to reflect the edit.
955+
if ($_->{OFS_DELTA}) {
956+
$ofs_delta += $_->{OFS_DELTA};
957+
}
948958
if (defined $last_o_ctx &&
949959
$o_ofs <= $last_o_ctx &&
950960
!$_->{DIRTY} &&
@@ -1016,6 +1026,30 @@ sub color_diff {
10161026
marked for applying."),
10171027
);
10181028

1029+
sub recount_edited_hunk {
1030+
local $_;
1031+
my ($oldtext, $newtext) = @_;
1032+
my ($o_cnt, $n_cnt) = (0, 0);
1033+
for (@{$newtext}[1..$#{$newtext}]) {
1034+
my $mode = substr($_, 0, 1);
1035+
if ($mode eq '-') {
1036+
$o_cnt++;
1037+
} elsif ($mode eq '+') {
1038+
$n_cnt++;
1039+
} elsif ($mode eq ' ') {
1040+
$o_cnt++;
1041+
$n_cnt++;
1042+
}
1043+
}
1044+
my ($o_ofs, undef, $n_ofs, undef) =
1045+
parse_hunk_header($newtext->[0]);
1046+
$newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
1047+
my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
1048+
parse_hunk_header($oldtext->[0]);
1049+
# Return the change in the number of lines inserted by this hunk
1050+
return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
1051+
}
1052+
10191053
sub edit_hunk_manually {
10201054
my ($oldtext) = @_;
10211055

@@ -1114,25 +1148,32 @@ sub prompt_yesno {
11141148
}
11151149

11161150
sub edit_hunk_loop {
1117-
my ($head, $hunk, $ix) = @_;
1118-
my $text = $hunk->[$ix]->{TEXT};
1151+
my ($head, $hunks, $ix) = @_;
1152+
my $hunk = $hunks->[$ix];
1153+
my $text = $hunk->{TEXT};
11191154

11201155
while (1) {
1121-
$text = edit_hunk_manually($text);
1122-
if (!defined $text) {
1156+
my $newtext = edit_hunk_manually($text);
1157+
if (!defined $newtext) {
11231158
return undef;
11241159
}
11251160
my $newhunk = {
1126-
TEXT => $text,
1127-
TYPE => $hunk->[$ix]->{TYPE},
1161+
TEXT => $newtext,
1162+
TYPE => $hunk->{TYPE},
11281163
USE => 1,
11291164
DIRTY => 1,
11301165
};
1166+
$newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
1167+
# If this hunk has already been edited then add the
1168+
# offset delta of the previous edit to get the real
1169+
# delta from the original unedited hunk.
1170+
$hunk->{OFS_DELTA} and
1171+
$newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
11311172
if (diff_applies($head,
1132-
@{$hunk}[0..$ix-1],
1173+
@{$hunks}[0..$ix-1],
11331174
$newhunk,
1134-
@{$hunk}[$ix+1..$#{$hunk}])) {
1135-
$newhunk->{DISPLAY} = [color_diff(@{$text})];
1175+
@{$hunks}[$ix+1..$#{$hunks}])) {
1176+
$newhunk->{DISPLAY} = [color_diff(@{$newtext})];
11361177
return $newhunk;
11371178
}
11381179
else {

t/t3701-add-interactive.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ test_expect_success 'add -p works with pathological context lines' '
504504
test_cmp expected-1 actual
505505
'
506506

507-
test_expect_failure 'add -p patch editing works with pathological context lines' '
507+
test_expect_success 'add -p patch editing works with pathological context lines' '
508508
git reset &&
509509
# n q q below is in case edit fails
510510
printf "%s\n" e y n q q |

0 commit comments

Comments
 (0)