apply: revamp the parsing of incomplete lines

A patch file represents the incomplete line at the end of the file with two lines, one that is the usual "context" with " " as the first letter, "added" with "+" as the first letter, or "removed" with "-" as the first letter that shows the content of the line, plus an extra "\ No newline at the end of file" line that comes immediately after it. Ever since the apply machinery was written, the "git apply" machinery parses "\ No newline at the end of file" line independently, without even knowing what line the incomplete-ness applies to, simply because it does not even remember what the previous line was. This poses a problem if we want to check and warn on an incomplete line. Revamp the code that parses a fragment, to actually drop the '\n' at the end of the incoming patch file that terminates a line, so that check_whitespace() calls made from the code path actually sees an incomplete as incomplete. Note that the result of this parsing is not directly used by the code path that applies the patch. apply_one_fragment() function already checks if each of the patch text it handles is followed by a line that begins with a backslash to drop the newline at the end of the current line it is looking at. In a sense, this patch harmonizes the behaviour of the parsing side to what is already done in the application side. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Nov 12, 2025 at 14:02 UTC 3a4eb5ad2e9166255d5921196470710523f24ec4
1 file changed +49 -21
apply.c
+49 -21
@@ -1670,6 +1670,35 @@ static void check_old_for_crlf(struct patch *patch, const char *line, int len)
1670 }
1671
1672
1673 +/*
1674 + * Just saw a single line in a fragment. If it is a part of this hunk
1675 + * that is a context " ", an added "+", or a removed "-" line, it may
1676 + * be followed by "\\ No newline..." to signal that the last "\n" on
1677 + * this line needs to be dropped. Depending on locale settings when
1678 + * the patch was produced we don't know what this line would exactly
1679 + * say. The only thing we do know is that it begins with "\ ".
1680 + * Checking for 12 is just for sanity check; "\ No newline..." would
1681 + * be at least that long in any l10n.
1682 + *
1683 + * Return 0 if the line we saw is not followed by "\ No newline...",
1684 + * or length of that line. The caller will use it to skip over the
1685 + * "\ No newline..." line.
1686 + */
1687 +static int adjust_incomplete(const char *line, int len,
1688 + unsigned long size)
1689 +{
1690 + int nextlen;
1691 +
1692 + if (*line != '\n' && *line != ' ' && *line != '+' && *line != '-')
1693 + return 0;
1694 + if (size - len < 12 || memcmp(line + len, "\\ ", 2))
1695 + return 0;
1696 + nextlen = linelen(line + len, size - len);
1697 + if (nextlen < 12)
1698 + return 0;
1699 + return nextlen;
1700 +}
1701 +
1702 /*
1703 * Parse a unified diff. Note that this really needs to parse each
1704 * fragment separately, since the only way to know the difference
@@ -1684,6 +1713,7 @@ static int parse_fragment(struct apply_state *state,
1713 {
1714 int added, deleted;
1715 int len = linelen(line, size), offset;
1716 + int skip_len = 0;
1717 unsigned long oldlines, newlines;
1718 unsigned long leading, trailing;
1719
@@ -1710,6 +1740,22 @@ static int parse_fragment(struct apply_state *state,
1740 len = linelen(line, size);
1741 if (!len || line[len-1] != '\n')
1742 return -1;
1743 +
1744 + /*
1745 + * For an incomplete line, skip_len counts the bytes
1746 + * on "\\ No newline..." marker line that comes next
1747 + * to the current line.
1748 + *
1749 + * Reduce "len" to drop the newline at the end of
1750 + * line[], but add one to "skip_len", which will be
1751 + * added back to "len" for the next iteration, to
1752 + * compensate.
1753 + */
1754 + skip_len = adjust_incomplete(line, len, size);
1755 + if (skip_len) {
1756 + len--;
1757 + skip_len++;
1758 + }
1759 switch (*line) {
1760 default:
1761 return -1;
@@ -1745,20 +1791,10 @@ static int parse_fragment(struct apply_state *state,
1791 newlines--;
1792 trailing = 0;
1793 break;
1748 -
1749 - /*
1750 - * We allow "\ No newline at end of file". Depending
1751 - * on locale settings when the patch was produced we
1752 - * don't know what this line looks like. The only
1753 - * thing we do know is that it begins with "\ ".
1754 - * Checking for 12 is just for sanity check -- any
1755 - * l10n of "\ No newline..." is at least that long.
1756 - */
1757 - case '\\':
1758 - if (len < 12 || memcmp(line, "\\ ", 2))
1759 - return -1;
1760 - break;
1794 }
1795 +
1796 + /* eat the "\\ No newline..." as well, if exists */
1797 + len += skip_len;
1798 }
1799 if (oldlines || newlines)
1800 return -1;
@@ -1768,14 +1804,6 @@ static int parse_fragment(struct apply_state *state,
1804 fragment->leading = leading;
1805 fragment->trailing = trailing;
1806
1771 - /*
1772 - * If a fragment ends with an incomplete line, we failed to include
1773 - * it in the above loop because we hit oldlines == newlines == 0
1774 - * before seeing it.
1775 - */
1776 - if (12 < size && !memcmp(line, "\\ ", 2))
1777 - offset += linelen(line, size);
1778 -
1807 patch->lines_added += added;
1808 patch->lines_deleted += deleted;
1809