Skip to content

Commit 7a26e65

Browse files
committed
Revert "git-add--interactive: remove hunk coalescing"
This reverts commit 0beee4c but with a bit of twist, as we have added "edit hunk manually" hack and we cannot rely on the original line numbers of the hunks that were manually edited. Signed-off-by: Junio C Hamano <[email protected]>
1 parent f67182b commit 7a26e65

File tree

2 files changed

+96
-2
lines changed

2 files changed

+96
-2
lines changed

git-add--interactive.perl

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,96 @@ sub split_hunk {
767767
return @split;
768768
}
769769

770+
sub find_last_o_ctx {
771+
my ($it) = @_;
772+
my $text = $it->{TEXT};
773+
my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
774+
my $i = @{$text};
775+
my $last_o_ctx = $o_ofs + $o_cnt;
776+
while (0 < --$i) {
777+
my $line = $text->[$i];
778+
if ($line =~ /^ /) {
779+
$last_o_ctx--;
780+
next;
781+
}
782+
last;
783+
}
784+
return $last_o_ctx;
785+
}
786+
787+
sub merge_hunk {
788+
my ($prev, $this) = @_;
789+
my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
790+
parse_hunk_header($prev->{TEXT}[0]);
791+
my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
792+
parse_hunk_header($this->{TEXT}[0]);
793+
794+
my (@line, $i, $ofs, $o_cnt, $n_cnt);
795+
$ofs = $o0_ofs;
796+
$o_cnt = $n_cnt = 0;
797+
for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
798+
my $line = $prev->{TEXT}[$i];
799+
if ($line =~ /^\+/) {
800+
$n_cnt++;
801+
push @line, $line;
802+
next;
803+
}
804+
805+
last if ($o1_ofs <= $ofs);
806+
807+
$o_cnt++;
808+
$ofs++;
809+
if ($line =~ /^ /) {
810+
$n_cnt++;
811+
}
812+
push @line, $line;
813+
}
814+
815+
for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
816+
my $line = $this->{TEXT}[$i];
817+
if ($line =~ /^\+/) {
818+
$n_cnt++;
819+
push @line, $line;
820+
next;
821+
}
822+
$ofs++;
823+
$o_cnt++;
824+
if ($line =~ /^ /) {
825+
$n_cnt++;
826+
}
827+
push @line, $line;
828+
}
829+
my $head = ("@@ -$o0_ofs" .
830+
(($o_cnt != 1) ? ",$o_cnt" : '') .
831+
" +$n0_ofs" .
832+
(($n_cnt != 1) ? ",$n_cnt" : '') .
833+
" @@\n");
834+
@{$prev->{TEXT}} = ($head, @line);
835+
}
836+
837+
sub coalesce_overlapping_hunks {
838+
my (@in) = @_;
839+
my @out = ();
840+
841+
my ($last_o_ctx, $last_was_dirty);
842+
843+
for (grep { $_->{USE} } @in) {
844+
my $text = $_->{TEXT};
845+
my ($o_ofs) = parse_hunk_header($text->[0]);
846+
if (defined $last_o_ctx &&
847+
$o_ofs <= $last_o_ctx &&
848+
!$_->{DIRTY} &&
849+
!$last_was_dirty) {
850+
merge_hunk($out[-1], $_);
851+
}
852+
else {
853+
push @out, $_;
854+
}
855+
$last_o_ctx = find_last_o_ctx($out[-1]);
856+
$last_was_dirty = $_->{DIRTY};
857+
}
858+
return @out;
859+
}
770860

771861
sub color_diff {
772862
return map {
@@ -878,7 +968,8 @@ sub edit_hunk_loop {
878968
my $newhunk = {
879969
TEXT => $text,
880970
TYPE => $hunk->[$ix]->{TYPE},
881-
USE => 1
971+
USE => 1,
972+
DIRTY => 1,
882973
};
883974
if (diff_applies($head,
884975
@{$hunk}[0..$ix-1],
@@ -1210,6 +1301,8 @@ sub patch_update_file {
12101301
}
12111302
}
12121303

1304+
@hunk = coalesce_overlapping_hunks(@hunk);
1305+
12131306
my $n_lofs = 0;
12141307
my @result = ();
12151308
for (@hunk) {
@@ -1224,6 +1317,7 @@ sub patch_update_file {
12241317
open $fh, '| git apply --cached --recount';
12251318
for (@{$head->{TEXT}}, @result) {
12261319
print $fh $_;
1320+
print STDERR $_;
12271321
}
12281322
if (!close $fh) {
12291323
for (@{$head->{TEXT}}, @result) {

t/t3701-add-interactive.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ index b6f2c08..61b9053 100755
189189
+lastline
190190
EOF
191191
# Test splitting the first patch, then adding both
192-
test_expect_failure 'add first line works' '
192+
test_expect_success 'add first line works' '
193193
git commit -am "clear local changes" &&
194194
git apply patch &&
195195
(echo s; echo y; echo y) | git add -p file &&

0 commit comments

Comments
 (0)