summaryrefslogtreecommitdiff
path: root/git-add--interactive.perl
diff options
context:
space:
mode:
authorPhillip Wood <phillip.wood@dunelm.org.uk>2020-09-09 13:58:52 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-09-09 19:49:01 (GMT)
commit75a009dc29d943554b39233286f02d34ead9a666 (patch)
treeea5487c5de763d39f768e666b965bbd81b5c96e9 /git-add--interactive.perl
parent3a238e539bcdfe3f9eb5010fd218640c1b499f7a (diff)
downloadgit-75a009dc29d943554b39233286f02d34ead9a666.zip
git-75a009dc29d943554b39233286f02d34ead9a666.tar.gz
git-75a009dc29d943554b39233286f02d34ead9a666.tar.bz2
add -p: fix editing of intent-to-add paths
A popular way of partially staging a new file is to run `git add -N <path>` and then use the hunk editing of `git add -p` to select the part of the file that the user wishes to stage. Since 85953a3187 ("diff-files --raw: show correct post-image of intent-to-add files", 2020-07-01) this has stopped working as intent-to-add paths are now show as new files rather than changes to an empty blob and `git apply` refused to apply a creation patch for a path that was marked as intent-to-add. 7cfde3fa0f ("apply: allow "new file" patches on i-t-a entries", 2020-08-06) fixed the problem with apply but it still wasn't possible to edit the added hunk properly. 2c8bd8471a ("checkout -p: handle new files correctly", 2020-05-27) had previously changed `add -p` to handle new files but it did not implement patch editing correctly. The perl version simply forbade editing and the C version opened the editor with the full diff rather that just the hunk which meant that the user had to edit the hunk header manually to get it to work. The root cause of the problem is that added files store the diff header with the hunk data rather than separating the two as we do for other changes. Changing added files to store the diff header separately fixes the editing problem at the expense of having to special case empty additions as they no longer have any hunks associated with them, only the diff header. The changes move some existing code into a conditional changing the indentation, they are best viewed with --color-moved-ws=allow-indentation-change (or --ignore-space-change works well to get an overview of the changes) Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Reported-by: Thomas Sullivan <tom@msbit.com.au> Reported-by: Yuchen Ying <ych@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'git-add--interactive.perl')
-rwxr-xr-xgit-add--interactive.perl89
1 files changed, 56 insertions, 33 deletions
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index f36c007..6771c0a 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -754,13 +754,16 @@ sub parse_diff_header {
my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' };
- my $addition = { TEXT => [], DISPLAY => [], TYPE => 'addition' };
+ my $addition;
for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
+ if ($src->{TEXT}->[$i] =~ /^new file/) {
+ $addition = 1;
+ $head->{TYPE} = 'addition';
+ }
my $dest =
$src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode :
$src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion :
- $src->{TEXT}->[$i] =~ /^new file/ ? $addition :
$head;
push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
@@ -1501,12 +1504,6 @@ sub patch_update_file {
push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
}
@hunk = ($deletion);
- } elsif (@{$addition->{TEXT}}) {
- foreach my $hunk (@hunk) {
- push @{$addition->{TEXT}}, @{$hunk->{TEXT}};
- push @{$addition->{DISPLAY}}, @{$hunk->{DISPLAY}};
- }
- @hunk = ($addition);
}
$num = scalar @hunk;
@@ -1516,6 +1513,7 @@ sub patch_update_file {
my ($prev, $next, $other, $undecided, $i);
$other = '';
+ last if ($ix and !$num);
if ($num <= $ix) {
$ix = 0;
}
@@ -1548,35 +1546,51 @@ sub patch_update_file {
last;
}
}
- last if (!$undecided);
+ last if (!$undecided && ($num || !$addition));
- if ($hunk[$ix]{TYPE} eq 'hunk' &&
- hunk_splittable($hunk[$ix]{TEXT})) {
- $other .= ',s';
- }
- if ($hunk[$ix]{TYPE} eq 'hunk') {
- $other .= ',e';
- }
- for (@{$hunk[$ix]{DISPLAY}}) {
- print;
+ if ($num) {
+ if ($hunk[$ix]{TYPE} eq 'hunk' &&
+ hunk_splittable($hunk[$ix]{TEXT})) {
+ $other .= ',s';
+ }
+ if ($hunk[$ix]{TYPE} eq 'hunk') {
+ $other .= ',e';
+ }
+ for (@{$hunk[$ix]{DISPLAY}}) {
+ print;
+ }
}
- print colored $prompt_color, "(", ($ix+1), "/$num) ",
- sprintf(__($patch_update_prompt_modes{$patch_mode}{$hunk[$ix]{TYPE}}), $other);
+ my $type = $num ? $hunk[$ix]{TYPE} : $head->{TYPE};
+ print colored $prompt_color, "(", ($ix+1), "/", ($num ? $num : 1), ") ",
+ sprintf(__($patch_update_prompt_modes{$patch_mode}{$type}), $other);
my $line = prompt_single_character;
last unless defined $line;
if ($line) {
if ($line =~ /^y/i) {
- $hunk[$ix]{USE} = 1;
+ if ($num) {
+ $hunk[$ix]{USE} = 1;
+ } else {
+ $head->{USE} = 1;
+ }
}
elsif ($line =~ /^n/i) {
- $hunk[$ix]{USE} = 0;
+ if ($num) {
+ $hunk[$ix]{USE} = 0;
+ } else {
+ $head->{USE} = 0;
+ }
}
elsif ($line =~ /^a/i) {
- while ($ix < $num) {
- if (!defined $hunk[$ix]{USE}) {
- $hunk[$ix]{USE} = 1;
+ if ($num) {
+ while ($ix < $num) {
+ if (!defined $hunk[$ix]{USE}) {
+ $hunk[$ix]{USE} = 1;
+ }
+ $ix++;
}
+ } else {
+ $head->{USE} = 1;
$ix++;
}
next;
@@ -1613,19 +1627,28 @@ sub patch_update_file {
next;
}
elsif ($line =~ /^d/i) {
- while ($ix < $num) {
- if (!defined $hunk[$ix]{USE}) {
- $hunk[$ix]{USE} = 0;
+ if ($num) {
+ while ($ix < $num) {
+ if (!defined $hunk[$ix]{USE}) {
+ $hunk[$ix]{USE} = 0;
+ }
+ $ix++;
}
+ } else {
+ $head->{USE} = 0;
$ix++;
}
next;
}
elsif ($line =~ /^q/i) {
- for ($i = 0; $i < $num; $i++) {
- if (!defined $hunk[$i]{USE}) {
- $hunk[$i]{USE} = 0;
+ if ($num) {
+ for ($i = 0; $i < $num; $i++) {
+ if (!defined $hunk[$i]{USE}) {
+ $hunk[$i]{USE} = 0;
+ }
}
+ } elsif (!defined $head->{USE}) {
+ $head->{USE} = 0;
}
$quit = 1;
last;
@@ -1743,7 +1766,7 @@ sub patch_update_file {
}
}
- @hunk = coalesce_overlapping_hunks(@hunk);
+ @hunk = coalesce_overlapping_hunks(@hunk) if ($num);
my $n_lofs = 0;
my @result = ();
@@ -1753,7 +1776,7 @@ sub patch_update_file {
}
}
- if (@result) {
+ if (@result or $head->{USE}) {
my @patch = reassemble_patch($head->{TEXT}, @result);
my $apply_routine = $patch_mode_flavour{APPLY};
&$apply_routine(@patch);