Skip to content

Commit 2bdf00e

Browse files
committed
Merge branch 'js/checkout-p-new-file'
"git checkout -p" did not handle a newly added path at all. * js/checkout-p-new-file: checkout -p: handle new files correctly
2 parents b37fd14 + 2c8bd84 commit 2bdf00e

File tree

3 files changed

+61
-9
lines changed

3 files changed

+61
-9
lines changed

add-patch.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "prompt.h"
1111

1212
enum prompt_mode_type {
13-
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
13+
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_ADDITION, PROMPT_HUNK,
1414
PROMPT_MODE_MAX, /* must be last */
1515
};
1616

@@ -33,6 +33,7 @@ static struct patch_mode patch_mode_add = {
3333
.prompt_mode = {
3434
N_("Stage mode change [y,n,q,a,d%s,?]? "),
3535
N_("Stage deletion [y,n,q,a,d%s,?]? "),
36+
N_("Stage addition [y,n,q,a,d%s,?]? "),
3637
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
3738
},
3839
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -54,6 +55,7 @@ static struct patch_mode patch_mode_stash = {
5455
.prompt_mode = {
5556
N_("Stash mode change [y,n,q,a,d%s,?]? "),
5657
N_("Stash deletion [y,n,q,a,d%s,?]? "),
58+
N_("Stash addition [y,n,q,a,d%s,?]? "),
5759
N_("Stash this hunk [y,n,q,a,d%s,?]? "),
5860
},
5961
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -77,6 +79,7 @@ static struct patch_mode patch_mode_reset_head = {
7779
.prompt_mode = {
7880
N_("Unstage mode change [y,n,q,a,d%s,?]? "),
7981
N_("Unstage deletion [y,n,q,a,d%s,?]? "),
82+
N_("Unstage addition [y,n,q,a,d%s,?]? "),
8083
N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
8184
},
8285
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -99,6 +102,7 @@ static struct patch_mode patch_mode_reset_nothead = {
99102
.prompt_mode = {
100103
N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
101104
N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
105+
N_("Apply addition to index [y,n,q,a,d%s,?]? "),
102106
N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
103107
},
104108
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -121,6 +125,7 @@ static struct patch_mode patch_mode_checkout_index = {
121125
.prompt_mode = {
122126
N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
123127
N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
128+
N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
124129
N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
125130
},
126131
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -143,6 +148,7 @@ static struct patch_mode patch_mode_checkout_head = {
143148
.prompt_mode = {
144149
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
145150
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
151+
N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
146152
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
147153
},
148154
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -164,6 +170,7 @@ static struct patch_mode patch_mode_checkout_nothead = {
164170
.prompt_mode = {
165171
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
166172
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
173+
N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
167174
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
168175
},
169176
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -186,6 +193,7 @@ static struct patch_mode patch_mode_worktree_head = {
186193
.prompt_mode = {
187194
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
188195
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
196+
N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
189197
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
190198
},
191199
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -207,6 +215,7 @@ static struct patch_mode patch_mode_worktree_nothead = {
207215
.prompt_mode = {
208216
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
209217
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
218+
N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
210219
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
211220
},
212221
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -248,7 +257,7 @@ struct add_p_state {
248257
struct hunk head;
249258
struct hunk *hunk;
250259
size_t hunk_nr, hunk_alloc;
251-
unsigned deleted:1, mode_change:1,binary:1;
260+
unsigned deleted:1, added:1, mode_change:1,binary:1;
252261
} *file_diff;
253262
size_t file_diff_nr;
254263

@@ -442,7 +451,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
442451
pend = p + plain->len;
443452
while (p != pend) {
444453
char *eol = memchr(p, '\n', pend - p);
445-
const char *deleted = NULL, *mode_change = NULL;
454+
const char *deleted = NULL, *added = NULL, *mode_change = NULL;
446455

447456
if (!eol)
448457
eol = pend;
@@ -461,11 +470,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
461470
} else if (p == plain->buf)
462471
BUG("diff starts with unexpected line:\n"
463472
"%.*s\n", (int)(eol - p), p);
464-
else if (file_diff->deleted)
473+
else if (file_diff->deleted || file_diff->added)
465474
; /* keep the rest of the file in a single "hunk" */
466475
else if (starts_with(p, "@@ ") ||
467476
(hunk == &file_diff->head &&
468-
skip_prefix(p, "deleted file", &deleted))) {
477+
(skip_prefix(p, "deleted file", &deleted) ||
478+
skip_prefix(p, "new file", &added)))) {
469479
if (marker == '-' || marker == '+')
470480
/*
471481
* Should not happen; previous hunk did not end
@@ -485,6 +495,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
485495

486496
if (deleted)
487497
file_diff->deleted = 1;
498+
else if (added)
499+
file_diff->added = 1;
488500
else if (parse_hunk_header(s, hunk) < 0)
489501
return -1;
490502

@@ -537,8 +549,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
537549
starts_with(p, "Binary files "))
538550
file_diff->binary = 1;
539551

540-
if (file_diff->deleted && file_diff->mode_change)
541-
BUG("diff contains delete *and* a mode change?!?\n%.*s",
552+
if (!!file_diff->deleted + !!file_diff->added +
553+
!!file_diff->mode_change > 1)
554+
BUG("diff can only contain delete *or* add *or* a "
555+
"mode change?!?\n%.*s",
542556
(int)(eol - (plain->buf + file_diff->head.start)),
543557
plain->buf + file_diff->head.start);
544558

@@ -1397,6 +1411,8 @@ static int patch_update_file(struct add_p_state *s,
13971411

13981412
if (file_diff->deleted)
13991413
prompt_mode_type = PROMPT_DELETION;
1414+
else if (file_diff->added)
1415+
prompt_mode_type = PROMPT_ADDITION;
14001416
else if (file_diff->mode_change && !hunk_index)
14011417
prompt_mode_type = PROMPT_MODE_CHANGE;
14021418
else

git-add--interactive.perl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,16 +754,18 @@ sub parse_diff_header {
754754
my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
755755
my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
756756
my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' };
757+
my $addition = { TEXT => [], DISPLAY => [], TYPE => 'addition' };
757758

758759
for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
759760
my $dest =
760761
$src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode :
761762
$src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion :
763+
$src->{TEXT}->[$i] =~ /^new file/ ? $addition :
762764
$head;
763765
push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
764766
push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
765767
}
766-
return ($head, $mode, $deletion);
768+
return ($head, $mode, $deletion, $addition);
767769
}
768770

769771
sub hunk_splittable {
@@ -1427,46 +1429,55 @@ sub display_hunks {
14271429
stage => {
14281430
mode => N__("Stage mode change [y,n,q,a,d%s,?]? "),
14291431
deletion => N__("Stage deletion [y,n,q,a,d%s,?]? "),
1432+
addition => N__("Stage addition [y,n,q,a,d%s,?]? "),
14301433
hunk => N__("Stage this hunk [y,n,q,a,d%s,?]? "),
14311434
},
14321435
stash => {
14331436
mode => N__("Stash mode change [y,n,q,a,d%s,?]? "),
14341437
deletion => N__("Stash deletion [y,n,q,a,d%s,?]? "),
1438+
addition => N__("Stash addition [y,n,q,a,d%s,?]? "),
14351439
hunk => N__("Stash this hunk [y,n,q,a,d%s,?]? "),
14361440
},
14371441
reset_head => {
14381442
mode => N__("Unstage mode change [y,n,q,a,d%s,?]? "),
14391443
deletion => N__("Unstage deletion [y,n,q,a,d%s,?]? "),
1444+
addition => N__("Unstage addition [y,n,q,a,d%s,?]? "),
14401445
hunk => N__("Unstage this hunk [y,n,q,a,d%s,?]? "),
14411446
},
14421447
reset_nothead => {
14431448
mode => N__("Apply mode change to index [y,n,q,a,d%s,?]? "),
14441449
deletion => N__("Apply deletion to index [y,n,q,a,d%s,?]? "),
1450+
addition => N__("Apply addition to index [y,n,q,a,d%s,?]? "),
14451451
hunk => N__("Apply this hunk to index [y,n,q,a,d%s,?]? "),
14461452
},
14471453
checkout_index => {
14481454
mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
14491455
deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
1456+
addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
14501457
hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
14511458
},
14521459
checkout_head => {
14531460
mode => N__("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
14541461
deletion => N__("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
1462+
addition => N__("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
14551463
hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
14561464
},
14571465
checkout_nothead => {
14581466
mode => N__("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
14591467
deletion => N__("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
1468+
addition => N__("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
14601469
hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
14611470
},
14621471
worktree_head => {
14631472
mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
14641473
deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
1474+
addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
14651475
hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
14661476
},
14671477
worktree_nothead => {
14681478
mode => N__("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
14691479
deletion => N__("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
1480+
addition => N__("Apply addition to worktree [y,n,q,a,d%s,?]? "),
14701481
hunk => N__("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
14711482
},
14721483
);
@@ -1476,7 +1487,7 @@ sub patch_update_file {
14761487
my ($ix, $num);
14771488
my $path = shift;
14781489
my ($head, @hunk) = parse_diff($path);
1479-
($head, my $mode, my $deletion) = parse_diff_header($head);
1490+
($head, my $mode, my $deletion, my $addition) = parse_diff_header($head);
14801491
for (@{$head->{DISPLAY}}) {
14811492
print;
14821493
}
@@ -1490,6 +1501,12 @@ sub patch_update_file {
14901501
push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
14911502
}
14921503
@hunk = ($deletion);
1504+
} elsif (@{$addition->{TEXT}}) {
1505+
foreach my $hunk (@hunk) {
1506+
push @{$addition->{TEXT}}, @{$hunk->{TEXT}};
1507+
push @{$addition->{DISPLAY}}, @{$hunk->{DISPLAY}};
1508+
}
1509+
@hunk = ($addition);
14931510
}
14941511

14951512
$num = scalar @hunk;

t/t3701-add-interactive.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,25 @@ test_expect_success 'deleting an empty file' '
412412
diff_cmp expected diff
413413
'
414414

415+
test_expect_success 'adding an empty file' '
416+
git init added &&
417+
(
418+
cd added &&
419+
test_commit initial &&
420+
>empty &&
421+
git add empty &&
422+
test_tick &&
423+
git commit -m empty &&
424+
git tag added-file &&
425+
git reset --hard HEAD^ &&
426+
test_path_is_missing empty &&
427+
428+
echo y | git checkout -p added-file -- >actual &&
429+
test_path_is_file empty &&
430+
test_i18ngrep "Apply addition to index and worktree" actual
431+
)
432+
'
433+
415434
test_expect_success 'split hunk setup' '
416435
git reset --hard &&
417436
test_write_lines 10 20 30 40 50 60 >test &&

0 commit comments

Comments
 (0)