Skip to content

Commit fb094cb

Browse files
committed
Merge branch 'js/add-p-diff-parsing-fix'
Those who use diff-so-fancy as the diff-filter noticed a regression or two in the code that parses the diff output in the built-in version of "add -p", which has been corrected. * js/add-p-diff-parsing-fix: add -p: ignore dirty submodules add -p: gracefully handle unparseable hunk headers in colored diffs add -p: detect more mismatches between plain vs colored diffs
2 parents 79f2338 + 0a10167 commit fb094cb

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

add-patch.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ struct hunk_header {
238238
* include the newline.
239239
*/
240240
size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
241+
unsigned suppress_colored_line_range:1;
241242
};
242243

243244
struct hunk {
@@ -358,15 +359,14 @@ static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
358359
if (!eol)
359360
eol = s->colored.buf + s->colored.len;
360361
p = memmem(line, eol - line, "@@ -", 4);
361-
if (!p)
362-
return error(_("could not parse colored hunk header '%.*s'"),
363-
(int)(eol - line), line);
364-
p = memmem(p + 4, eol - p - 4, " @@", 3);
365-
if (!p)
366-
return error(_("could not parse colored hunk header '%.*s'"),
367-
(int)(eol - line), line);
362+
if (p && (p = memmem(p + 4, eol - p - 4, " @@", 3))) {
363+
header->colored_extra_start = p + 3 - s->colored.buf;
364+
} else {
365+
/* could not parse colored hunk header, leave as-is */
366+
header->colored_extra_start = hunk->colored_start;
367+
header->suppress_colored_line_range = 1;
368+
}
368369
hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
369-
header->colored_extra_start = p + 3 - s->colored.buf;
370370
header->colored_extra_end = hunk->colored_start;
371371

372372
return 0;
@@ -419,7 +419,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
419419
}
420420
color_arg_index = args.nr;
421421
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
422-
strvec_pushl(&args, "--no-color", "-p", "--", NULL);
422+
strvec_pushl(&args, "--no-color", "--ignore-submodules=dirty", "-p",
423+
"--", NULL);
423424
for (i = 0; i < ps->nr; i++)
424425
strvec_push(&args, ps->items[i].original);
425426

@@ -592,7 +593,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
592593
if (colored_eol)
593594
colored_p = colored_eol + 1;
594595
else if (p != pend)
595-
/* colored shorter than non-colored? */
596+
/* non-colored has more lines? */
597+
goto mismatched_output;
598+
else if (colored_p == colored_pend)
599+
/* last line has no matching colored one? */
596600
goto mismatched_output;
597601
else
598602
colored_p = colored_pend;
@@ -656,6 +660,15 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
656660
if (!colored) {
657661
p = s->plain.buf + header->extra_start;
658662
len = header->extra_end - header->extra_start;
663+
} else if (header->suppress_colored_line_range) {
664+
strbuf_add(out,
665+
s->colored.buf + header->colored_extra_start,
666+
header->colored_extra_end -
667+
header->colored_extra_start);
668+
669+
strbuf_add(out, s->colored.buf + hunk->colored_start,
670+
hunk->colored_end - hunk->colored_start);
671+
return;
659672
} else {
660673
strbuf_addstr(out, s->s.fraginfo_color);
661674
p = s->colored.buf + header->colored_extra_start;

t/t3701-add-interactive.sh

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,20 @@ test_expect_success 'detect bogus diffFilter output' '
761761
git reset --hard &&
762762
763763
echo content >test &&
764-
test_config interactive.diffFilter "sed 1d" &&
764+
test_config interactive.diffFilter "sed 6d" &&
765765
printf y >y &&
766-
force_color test_must_fail git add -p <y
766+
force_color test_must_fail git add -p <y >output 2>&1 &&
767+
grep "mismatched output" output
768+
'
769+
770+
test_expect_success 'handle iffy colored hunk headers' '
771+
git reset --hard &&
772+
773+
echo content >test &&
774+
printf n >n &&
775+
force_color git -c interactive.diffFilter="sed s/.*@@.*/XX/" \
776+
add -p >output 2>&1 <n &&
777+
grep "^XX$" output
767778
'
768779

769780
test_expect_success 'handle very large filtered diff' '
@@ -944,6 +955,18 @@ test_expect_success 'status ignores dirty submodules (except HEAD)' '
944955
! grep dirty-otherwise output
945956
'
946957

958+
test_expect_success 'handle submodules' '
959+
echo 123 >>for-submodules/dirty-otherwise/initial.t &&
960+
961+
force_color git -C for-submodules add -p dirty-otherwise >output 2>&1 &&
962+
grep "No changes" output &&
963+
964+
force_color git -C for-submodules add -p dirty-head >output 2>&1 <y &&
965+
git -C for-submodules ls-files --stage dirty-head >actual &&
966+
rev="$(git -C for-submodules/dirty-head rev-parse HEAD)" &&
967+
grep "$rev" actual
968+
'
969+
947970
test_expect_success 'set up pathological context' '
948971
git reset --hard &&
949972
test_write_lines a a a a a a a a a a a >a &&

0 commit comments

Comments
 (0)