Skip to content

Fix a bug in the hunk-splitting code of the built-in git add -p #2368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions add-patch.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,10 +511,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
(int)(eol - (plain->buf + file_diff->head.start)),
plain->buf + file_diff->head.start);

if ((marker == '-' || marker == '+') &&
(*p == ' ' || *p == '\\'))
if ((marker == '-' || marker == '+') && *p == ' ')
hunk->splittable_into++;
if (marker)
if (marker && *p != '\\')
marker = *p;

p = eol == pend ? pend : eol + 1;
Expand Down Expand Up @@ -563,8 +562,13 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)

static size_t find_next_line(struct strbuf *sb, size_t offset)
{
char *eol = memchr(sb->buf + offset, '\n', sb->len - offset);
char *eol;

if (offset >= sb->len)
BUG("looking for next line beyond buffer (%d >= %d)\n%s",
(int)offset, (int)sb->len, sb->buf);

eol = memchr(sb->buf + offset, '\n', sb->len - offset);
if (!eol)
return sb->len;
return eol - sb->buf + 1;
Expand Down Expand Up @@ -849,6 +853,14 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,

while (splittable_into > 1) {
ch = s->plain.buf[current];

if (!ch)
BUG("buffer overrun while splitting hunks");

/*
* Is this the first context line after a chain of +/- lines?
* Then record the start of the next split hunk.
*/
if ((marker == '-' || marker == '+') && ch == ' ') {
first = 0;
hunk[1].start = current;
Expand All @@ -857,8 +869,22 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
context_line_count = 0;
}

/*
* Was the previous line a +/- one? Alternatively, is this the
* first line (and not a +/- one)?
*
* Then just increment the appropriate counter and continue
* with the next line.
*
* Otherwise this is the first of a chain of +/- lines.
* neither the first of a chain of context lines?
*/
if (marker != ' ' || (ch != '-' && ch != '+')) {
next_hunk_line:
/* Comment lines are attached to the previous line */
if (ch == '\\')
ch = marker ? marker : ' ';

/* current hunk not done yet */
if (ch == ' ')
context_line_count++;
Expand Down
12 changes: 12 additions & 0 deletions t/t3701-add-interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,18 @@ test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
! grep "^+31" actual
'

test_expect_success 'split hunk with incomplete line at end' '
git reset --hard &&
printf "missing LF" >>test &&
git add test &&
test_write_lines before 10 20 30 40 50 60 70 >test &&
git grep --cached missing &&
test_write_lines s n y q | git add -p &&
test_must_fail git grep --cached missing &&
git grep before &&
test_must_fail git grep --cached before
'

test_expect_failure 'edit, adding lines to the first hunk' '
test_write_lines 10 11 20 30 40 50 51 60 >test &&
git reset &&
Expand Down