Skip to content

Commit 3f855fe

Browse files
committed
patch_parse: handle missing newline indicator in old file
When either the old or new file contents have no newline at the end of the file, then git-diff(1) will print out a "\ No newline at end of file" indicator. While we do correctly handle this in the case where the new file has this indcator, we fail to parse patches where the old file is missing a newline at EOF. Fix this bug by handling and missing newline indicators in the old file. Add tests to verify that we can parse such files.
1 parent b30dab8 commit 3f855fe

File tree

3 files changed

+36
-1
lines changed

3 files changed

+36
-1
lines changed

src/patch_parse.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,16 @@ static int parse_hunk_body(
578578
old_lineno = -1;
579579
break;
580580

581+
case '\\':
582+
/*
583+
* If there are no oldlines left, then this is probably
584+
* the "\ No newline at end of file" marker. Do not
585+
* verify its format, as it may be localized.
586+
*/
587+
if (!oldlines)
588+
continue;
589+
/* fall through */
590+
581591
default:
582592
error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
583593
goto done;
@@ -606,7 +616,8 @@ static int parse_hunk_body(
606616
goto done;
607617
}
608618

609-
/* Handle "\ No newline at end of file". Only expect the leading
619+
/*
620+
* Handle "\ No newline at end of file". Only expect the leading
610621
* backslash, though, because the rest of the string could be
611622
* localized. Because `diff` optimizes for the case where you
612623
* want to apply the patch by hand.

tests/patch/parse.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ void test_patch_parse__invalid_patches_fails(void)
102102
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
103103
}
104104

105+
void test_patch_parse__no_newline_at_end_of_new_file(void)
106+
{
107+
git_patch *patch;
108+
cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL, strlen(PATCH_APPEND_NO_NL), NULL));
109+
git_patch_free(patch);
110+
}
111+
112+
void test_patch_parse__no_newline_at_end_of_old_file(void)
113+
{
114+
git_patch *patch;
115+
cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL_IN_OLD_FILE, strlen(PATCH_APPEND_NO_NL_IN_OLD_FILE), NULL));
116+
git_patch_free(patch);
117+
}
118+
105119
void test_patch_parse__files_with_whitespaces_succeeds(void)
106120
{
107121
git_patch *patch;

tests/patch/patch_common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,16 @@
681681
"+added line with no nl\n" \
682682
"\\ No newline at end of file\n"
683683

684+
#define PATCH_APPEND_NO_NL_IN_OLD_FILE \
685+
"diff --git a/file.txt b/file.txt\n" \
686+
"index 9432026..83759c0 100644\n" \
687+
"--- a/file.txt\n" \
688+
"+++ b/file.txt\n" \
689+
"@@ -1,1 +1,1 @@\n" \
690+
"-foo\n" \
691+
"\\ No newline at end of file\n" \
692+
"+foo\n"
693+
684694
#define PATCH_NAME_WHITESPACE \
685695
"diff --git a/file with spaces.txt b/file with spaces.txt\n" \
686696
"index 9432026..83759c0 100644\n" \

0 commit comments

Comments
 (0)