Skip to content

Commit 5166714

Browse files
bjornggitster
authored andcommitted
apply: Allow blank context lines to match beyond EOF
"git apply --whitespace=fix" will not always succeed when used on a series of patches in the following circumstances: * One patch adds a blank line at the end of a file. (Since --whitespace=fix is used, the blank line will *not* be added.) * The next patch adds non-blank lines after the blank line introduced in the first patch. That patch will not apply because the blank line that is expected to be found at end of the file is no longer there. A patch series that starts by deleting lines at the end will fail in a similar way. Fix this problem by allowing a blank context line at the beginning of a hunk to match if parts of it falls beyond end of the file. We still require that at least one non-blank context line match before the end of the file. If the --ignore-space-change option is given (as well as the --whitespace=fix option), blank context lines falling beyond the end of the file will be copied unchanged to the target file (i.e. they will have the same line terminators and extra spaces will not be removed). Signed-off-by: Björn Gustavsson <bgustavsson@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 24ff4d5 commit 5166714

1 file changed

Lines changed: 138 additions & 30 deletions

File tree

builtin-apply.c

Lines changed: 138 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,33 +1854,76 @@ static int match_fragment(struct image *img,
18541854
{
18551855
int i;
18561856
char *fixed_buf, *buf, *orig, *target;
1857+
int preimage_limit;
18571858

1858-
if (preimage->nr + try_lno > img->nr)
1859+
if (preimage->nr + try_lno <= img->nr) {
1860+
/*
1861+
* The hunk falls within the boundaries of img.
1862+
*/
1863+
preimage_limit = preimage->nr;
1864+
if (match_end && (preimage->nr + try_lno != img->nr))
1865+
return 0;
1866+
} else if (ws_error_action == correct_ws_error &&
1867+
(ws_rule & WS_BLANK_AT_EOF) && match_end) {
1868+
/*
1869+
* This hunk that matches at the end extends beyond
1870+
* the end of img, and we are removing blank lines
1871+
* at the end of the file. This many lines from the
1872+
* beginning of the preimage must match with img, and
1873+
* the remainder of the preimage must be blank.
1874+
*/
1875+
preimage_limit = img->nr - try_lno;
1876+
} else {
1877+
/*
1878+
* The hunk extends beyond the end of the img and
1879+
* we are not removing blanks at the end, so we
1880+
* should reject the hunk at this position.
1881+
*/
18591882
return 0;
1883+
}
18601884

18611885
if (match_beginning && try_lno)
18621886
return 0;
18631887

1864-
if (match_end && preimage->nr + try_lno != img->nr)
1865-
return 0;
1866-
18671888
/* Quick hash check */
1868-
for (i = 0; i < preimage->nr; i++)
1889+
for (i = 0; i < preimage_limit; i++)
18691890
if (preimage->line[i].hash != img->line[try_lno + i].hash)
18701891
return 0;
18711892

1872-
/*
1873-
* Do we have an exact match? If we were told to match
1874-
* at the end, size must be exactly at try+fragsize,
1875-
* otherwise try+fragsize must be still within the preimage,
1876-
* and either case, the old piece should match the preimage
1877-
* exactly.
1878-
*/
1879-
if ((match_end
1880-
? (try + preimage->len == img->len)
1881-
: (try + preimage->len <= img->len)) &&
1882-
!memcmp(img->buf + try, preimage->buf, preimage->len))
1883-
return 1;
1893+
if (preimage_limit == preimage->nr) {
1894+
/*
1895+
* Do we have an exact match? If we were told to match
1896+
* at the end, size must be exactly at try+fragsize,
1897+
* otherwise try+fragsize must be still within the preimage,
1898+
* and either case, the old piece should match the preimage
1899+
* exactly.
1900+
*/
1901+
if ((match_end
1902+
? (try + preimage->len == img->len)
1903+
: (try + preimage->len <= img->len)) &&
1904+
!memcmp(img->buf + try, preimage->buf, preimage->len))
1905+
return 1;
1906+
} else {
1907+
/*
1908+
* The preimage extends beyond the end of img, so
1909+
* there cannot be an exact match.
1910+
*
1911+
* There must be one non-blank context line that match
1912+
* a line before the end of img.
1913+
*/
1914+
char *buf_end;
1915+
1916+
buf = preimage->buf;
1917+
buf_end = buf;
1918+
for (i = 0; i < preimage_limit; i++)
1919+
buf_end += preimage->line[i].len;
1920+
1921+
for ( ; buf < buf_end; buf++)
1922+
if (!isspace(*buf))
1923+
break;
1924+
if (buf == buf_end)
1925+
return 0;
1926+
}
18841927

18851928
/*
18861929
* No exact match. If we are ignoring whitespace, run a line-by-line
@@ -1891,7 +1934,10 @@ static int match_fragment(struct image *img,
18911934
size_t imgoff = 0;
18921935
size_t preoff = 0;
18931936
size_t postlen = postimage->len;
1894-
for (i = 0; i < preimage->nr; i++) {
1937+
size_t extra_chars;
1938+
char *preimage_eof;
1939+
char *preimage_end;
1940+
for (i = 0; i < preimage_limit; i++) {
18951941
size_t prelen = preimage->line[i].len;
18961942
size_t imglen = img->line[try_lno+i].len;
18971943

@@ -1908,12 +1954,33 @@ static int match_fragment(struct image *img,
19081954
* Ok, the preimage matches with whitespace fuzz.
19091955
*
19101956
* imgoff now holds the true length of the target that
1911-
* matches the preimage. Update the preimage and
1912-
* the common postimage context lines to use the same
1913-
* whitespace as the target.
1957+
* matches the preimage before the end of the file.
1958+
*
1959+
* Count the number of characters in the preimage that fall
1960+
* beyond the end of the file and make sure that all of them
1961+
* are whitespace characters. (This can only happen if
1962+
* we are removing blank lines at the end of the file.)
19141963
*/
1915-
fixed_buf = xmalloc(imgoff);
1964+
buf = preimage_eof = preimage->buf + preoff;
1965+
for ( ; i < preimage->nr; i++)
1966+
preoff += preimage->line[i].len;
1967+
preimage_end = preimage->buf + preoff;
1968+
for ( ; buf < preimage_end; buf++)
1969+
if (!isspace(*buf))
1970+
return 0;
1971+
1972+
/*
1973+
* Update the preimage and the common postimage context
1974+
* lines to use the same whitespace as the target.
1975+
* If whitespace is missing in the target (i.e.
1976+
* if the preimage extends beyond the end of the file),
1977+
* use the whitespace from the preimage.
1978+
*/
1979+
extra_chars = preimage_end - preimage_eof;
1980+
fixed_buf = xmalloc(imgoff + extra_chars);
19161981
memcpy(fixed_buf, img->buf + try, imgoff);
1982+
memcpy(fixed_buf + imgoff, preimage_eof, extra_chars);
1983+
imgoff += extra_chars;
19171984
update_pre_post_images(preimage, postimage,
19181985
fixed_buf, imgoff, postlen);
19191986
return 1;
@@ -1927,12 +1994,16 @@ static int match_fragment(struct image *img,
19271994
* it might with whitespace fuzz. We haven't been asked to
19281995
* ignore whitespace, we were asked to correct whitespace
19291996
* errors, so let's try matching after whitespace correction.
1997+
*
1998+
* The preimage may extend beyond the end of the file,
1999+
* but in this loop we will only handle the part of the
2000+
* preimage that falls within the file.
19302001
*/
19312002
fixed_buf = xmalloc(preimage->len + 1);
19322003
buf = fixed_buf;
19332004
orig = preimage->buf;
19342005
target = img->buf + try;
1935-
for (i = 0; i < preimage->nr; i++) {
2006+
for (i = 0; i < preimage_limit; i++) {
19362007
size_t fixlen; /* length after fixing the preimage */
19372008
size_t oldlen = preimage->line[i].len;
19382009
size_t tgtlen = img->line[try_lno + i].len;
@@ -1972,6 +2043,29 @@ static int match_fragment(struct image *img,
19722043
target += tgtlen;
19732044
}
19742045

2046+
2047+
/*
2048+
* Now handle the lines in the preimage that falls beyond the
2049+
* end of the file (if any). They will only match if they are
2050+
* empty or only contain whitespace (if WS_BLANK_AT_EOL is
2051+
* false).
2052+
*/
2053+
for ( ; i < preimage->nr; i++) {
2054+
size_t fixlen; /* length after fixing the preimage */
2055+
size_t oldlen = preimage->line[i].len;
2056+
int j;
2057+
2058+
/* Try fixing the line in the preimage */
2059+
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
2060+
2061+
for (j = 0; j < fixlen; j++)
2062+
if (!isspace(buf[j]))
2063+
goto unmatch_exit;
2064+
2065+
orig += oldlen;
2066+
buf += fixlen;
2067+
}
2068+
19752069
/*
19762070
* Yes, the preimage is based on an older version that still
19772071
* has whitespace breakages unfixed, and fixing them makes the
@@ -2088,12 +2182,26 @@ static void update_image(struct image *img,
20882182
int i, nr;
20892183
size_t remove_count, insert_count, applied_at = 0;
20902184
char *result;
2185+
int preimage_limit;
2186+
2187+
/*
2188+
* If we are removing blank lines at the end of img,
2189+
* the preimage may extend beyond the end.
2190+
* If that is the case, we must be careful only to
2191+
* remove the part of the preimage that falls within
2192+
* the boundaries of img. Initialize preimage_limit
2193+
* to the number of lines in the preimage that falls
2194+
* within the boundaries.
2195+
*/
2196+
preimage_limit = preimage->nr;
2197+
if (preimage_limit > img->nr - applied_pos)
2198+
preimage_limit = img->nr - applied_pos;
20912199

20922200
for (i = 0; i < applied_pos; i++)
20932201
applied_at += img->line[i].len;
20942202

20952203
remove_count = 0;
2096-
for (i = 0; i < preimage->nr; i++)
2204+
for (i = 0; i < preimage_limit; i++)
20972205
remove_count += img->line[applied_pos + i].len;
20982206
insert_count = postimage->len;
20992207

@@ -2110,19 +2218,19 @@ static void update_image(struct image *img,
21102218
result[img->len] = '\0';
21112219

21122220
/* Adjust the line table */
2113-
nr = img->nr + postimage->nr - preimage->nr;
2114-
if (preimage->nr < postimage->nr) {
2221+
nr = img->nr + postimage->nr - preimage_limit;
2222+
if (preimage_limit < postimage->nr) {
21152223
/*
21162224
* NOTE: this knows that we never call remove_first_line()
21172225
* on anything other than pre/post image.
21182226
*/
21192227
img->line = xrealloc(img->line, nr * sizeof(*img->line));
21202228
img->line_allocated = img->line;
21212229
}
2122-
if (preimage->nr != postimage->nr)
2230+
if (preimage_limit != postimage->nr)
21232231
memmove(img->line + applied_pos + postimage->nr,
2124-
img->line + applied_pos + preimage->nr,
2125-
(img->nr - (applied_pos + preimage->nr)) *
2232+
img->line + applied_pos + preimage_limit,
2233+
(img->nr - (applied_pos + preimage_limit)) *
21262234
sizeof(*img->line));
21272235
memcpy(img->line + applied_pos,
21282236
postimage->line,
@@ -2318,7 +2426,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
23182426

23192427
if (applied_pos >= 0) {
23202428
if (new_blank_lines_at_end &&
2321-
preimage.nr + applied_pos == img->nr &&
2429+
preimage.nr + applied_pos >= img->nr &&
23222430
(ws_rule & WS_BLANK_AT_EOF) &&
23232431
ws_error_action != nowarn_ws_error) {
23242432
record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);

0 commit comments

Comments
 (0)