Merge branch 'pw/add-p-recount'
"git add -p" has been lazy in coalescing split patches before passing the result to underlying "git apply", leading to corner case bugs; the logic to prepare the patch to be applied after hunk selections has been tightened. * pw/add-p-recount: add -p: don't rely on apply's '--recount' option add -p: fix counting when splitting and coalescing add -p: calculate offset delta for edited patches add -p: adjust offsets of subsequent hunks when one is skipped t3701: add failing test for pathological context lines t3701: don't hard code sha1 hash values t3701: use test_write_lines and write_script t3701: indent here documents add -i: add function to format hunk header
This commit is contained in:
@ -677,7 +677,7 @@ sub add_untracked_cmd {
|
||||
sub run_git_apply {
|
||||
my $cmd = shift;
|
||||
my $fh;
|
||||
open $fh, '| git ' . $cmd . " --recount --allow-overlap";
|
||||
open $fh, '| git ' . $cmd . " --allow-overlap";
|
||||
print $fh @_;
|
||||
return close $fh;
|
||||
}
|
||||
@ -751,6 +751,15 @@ sub parse_hunk_header {
|
||||
return ($o_ofs, $o_cnt, $n_ofs, $n_cnt);
|
||||
}
|
||||
|
||||
sub format_hunk_header {
|
||||
my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = @_;
|
||||
return ("@@ -$o_ofs" .
|
||||
(($o_cnt != 1) ? ",$o_cnt" : '') .
|
||||
" +$n_ofs" .
|
||||
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
||||
" @@\n");
|
||||
}
|
||||
|
||||
sub split_hunk {
|
||||
my ($text, $display) = @_;
|
||||
my @split = ();
|
||||
@ -784,6 +793,11 @@ sub split_hunk {
|
||||
while (++$i < @$text) {
|
||||
my $line = $text->[$i];
|
||||
my $display = $display->[$i];
|
||||
if ($line =~ /^\\/) {
|
||||
push @{$this->{TEXT}}, $line;
|
||||
push @{$this->{DISPLAY}}, $display;
|
||||
next;
|
||||
}
|
||||
if ($line =~ /^ /) {
|
||||
if ($this->{ADDDEL} &&
|
||||
!defined $next_hunk_start) {
|
||||
@ -838,11 +852,7 @@ sub split_hunk {
|
||||
my $o_cnt = $hunk->{OCNT};
|
||||
my $n_cnt = $hunk->{NCNT};
|
||||
|
||||
my $head = ("@@ -$o_ofs" .
|
||||
(($o_cnt != 1) ? ",$o_cnt" : '') .
|
||||
" +$n_ofs" .
|
||||
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
||||
" @@\n");
|
||||
my $head = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
|
||||
my $display_head = $head;
|
||||
unshift @{$hunk->{TEXT}}, $head;
|
||||
if ($diff_use_color) {
|
||||
@ -886,6 +896,9 @@ sub merge_hunk {
|
||||
$n_cnt++;
|
||||
push @line, $line;
|
||||
next;
|
||||
} elsif ($line =~ /^\\/) {
|
||||
push @line, $line;
|
||||
next;
|
||||
}
|
||||
|
||||
last if ($o1_ofs <= $ofs);
|
||||
@ -904,6 +917,9 @@ sub merge_hunk {
|
||||
$n_cnt++;
|
||||
push @line, $line;
|
||||
next;
|
||||
} elsif ($line =~ /^\\/) {
|
||||
push @line, $line;
|
||||
next;
|
||||
}
|
||||
$ofs++;
|
||||
$o_cnt++;
|
||||
@ -912,11 +928,7 @@ sub merge_hunk {
|
||||
}
|
||||
push @line, $line;
|
||||
}
|
||||
my $head = ("@@ -$o0_ofs" .
|
||||
(($o_cnt != 1) ? ",$o_cnt" : '') .
|
||||
" +$n0_ofs" .
|
||||
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
||||
" @@\n");
|
||||
my $head = format_hunk_header($o0_ofs, $o_cnt, $n0_ofs, $n_cnt);
|
||||
@{$prev->{TEXT}} = ($head, @line);
|
||||
}
|
||||
|
||||
@ -925,14 +937,35 @@ sub coalesce_overlapping_hunks {
|
||||
my @out = ();
|
||||
|
||||
my ($last_o_ctx, $last_was_dirty);
|
||||
my $ofs_delta = 0;
|
||||
|
||||
for (grep { $_->{USE} } @in) {
|
||||
for (@in) {
|
||||
if ($_->{TYPE} ne 'hunk') {
|
||||
push @out, $_;
|
||||
next;
|
||||
}
|
||||
my $text = $_->{TEXT};
|
||||
my ($o_ofs) = parse_hunk_header($text->[0]);
|
||||
my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
|
||||
parse_hunk_header($text->[0]);
|
||||
unless ($_->{USE}) {
|
||||
$ofs_delta += $o_cnt - $n_cnt;
|
||||
# If this hunk has been edited then subtract
|
||||
# the delta that is due to the edit.
|
||||
if ($_->{OFS_DELTA}) {
|
||||
$ofs_delta -= $_->{OFS_DELTA};
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($ofs_delta) {
|
||||
$n_ofs += $ofs_delta;
|
||||
$_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
|
||||
$n_ofs, $n_cnt);
|
||||
}
|
||||
# If this hunk was edited then adjust the offset delta
|
||||
# to reflect the edit.
|
||||
if ($_->{OFS_DELTA}) {
|
||||
$ofs_delta += $_->{OFS_DELTA};
|
||||
}
|
||||
if (defined $last_o_ctx &&
|
||||
$o_ofs <= $last_o_ctx &&
|
||||
!$_->{DIRTY} &&
|
||||
@ -1004,6 +1037,30 @@ marked for discarding."),
|
||||
marked for applying."),
|
||||
);
|
||||
|
||||
sub recount_edited_hunk {
|
||||
local $_;
|
||||
my ($oldtext, $newtext) = @_;
|
||||
my ($o_cnt, $n_cnt) = (0, 0);
|
||||
for (@{$newtext}[1..$#{$newtext}]) {
|
||||
my $mode = substr($_, 0, 1);
|
||||
if ($mode eq '-') {
|
||||
$o_cnt++;
|
||||
} elsif ($mode eq '+') {
|
||||
$n_cnt++;
|
||||
} elsif ($mode eq ' ') {
|
||||
$o_cnt++;
|
||||
$n_cnt++;
|
||||
}
|
||||
}
|
||||
my ($o_ofs, undef, $n_ofs, undef) =
|
||||
parse_hunk_header($newtext->[0]);
|
||||
$newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
|
||||
my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
|
||||
parse_hunk_header($oldtext->[0]);
|
||||
# Return the change in the number of lines inserted by this hunk
|
||||
return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
|
||||
}
|
||||
|
||||
sub edit_hunk_manually {
|
||||
my ($oldtext) = @_;
|
||||
|
||||
@ -1102,25 +1159,32 @@ sub prompt_yesno {
|
||||
}
|
||||
|
||||
sub edit_hunk_loop {
|
||||
my ($head, $hunk, $ix) = @_;
|
||||
my $text = $hunk->[$ix]->{TEXT};
|
||||
my ($head, $hunks, $ix) = @_;
|
||||
my $hunk = $hunks->[$ix];
|
||||
my $text = $hunk->{TEXT};
|
||||
|
||||
while (1) {
|
||||
$text = edit_hunk_manually($text);
|
||||
if (!defined $text) {
|
||||
my $newtext = edit_hunk_manually($text);
|
||||
if (!defined $newtext) {
|
||||
return undef;
|
||||
}
|
||||
my $newhunk = {
|
||||
TEXT => $text,
|
||||
TYPE => $hunk->[$ix]->{TYPE},
|
||||
TEXT => $newtext,
|
||||
TYPE => $hunk->{TYPE},
|
||||
USE => 1,
|
||||
DIRTY => 1,
|
||||
};
|
||||
$newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
|
||||
# If this hunk has already been edited then add the
|
||||
# offset delta of the previous edit to get the real
|
||||
# delta from the original unedited hunk.
|
||||
$hunk->{OFS_DELTA} and
|
||||
$newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
|
||||
if (diff_applies($head,
|
||||
@{$hunk}[0..$ix-1],
|
||||
@{$hunks}[0..$ix-1],
|
||||
$newhunk,
|
||||
@{$hunk}[$ix+1..$#{$hunk}])) {
|
||||
$newhunk->{DISPLAY} = [color_diff(@{$text})];
|
||||
@{$hunks}[$ix+1..$#{$hunks}])) {
|
||||
$newhunk->{DISPLAY} = [color_diff(@{$newtext})];
|
||||
return $newhunk;
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user